changeset 52575:9ca9aa224c39

Merge
author psadhukhan
date Wed, 14 Nov 2018 17:16:44 +0530
parents 1a62b3420c27 6f18c23b0185
children 5f1ca46703f9 d569b5e29021
files src/java.base/share/classes/jdk/internal/org/objectweb/asm/Item.java
diffstat 357 files changed, 33553 insertions(+), 29361 deletions(-) [+]
line wrap: on
line diff
--- a/bin/idea.sh	Mon Nov 12 12:39:03 2018 +0530
+++ b/bin/idea.sh	Wed Nov 14 17:16:44 2018 +0530
@@ -136,17 +136,33 @@
     eval TO$NUM_REPLACEMENTS='$2'
 }
 
-add_replacement "###BUILD_DIR###" "`dirname $SPEC`"
 add_replacement "###MODULE_NAMES###" "$MODULE_NAMES"
-add_replacement "###JTREG_HOME###" "$JT_HOME"
-add_replacement "###IMAGES_DIR###" "`dirname $SPEC`/images/jdk"
-add_replacement "###ROOT_DIR###" "$TOPLEVEL_DIR"
-add_replacement "###IDEA_DIR###" "$IDEA_OUTPUT"
+SPEC_DIR=`dirname $SPEC`
+if [ "x$CYGPATH" = "x" ]; then
+    add_replacement "###BUILD_DIR###" "$SPEC_DIR"
+    add_replacement "###JTREG_HOME###" "$JT_HOME"
+    add_replacement "###IMAGES_DIR###" "$SPEC_DIR/images/jdk"
+    add_replacement "###ROOT_DIR###" "$TOPLEVEL_DIR"
+    add_replacement "###IDEA_DIR###" "$IDEA_OUTPUT"
+else
+    add_replacement "###BUILD_DIR###" "`cygpath -am $SPEC_DIR`"
+    add_replacement "###IMAGES_DIR###" "`cygpath -am $SPEC_DIR`/images/jdk"
+    add_replacement "###ROOT_DIR###" "`cygpath -am $TOPLEVEL_DIR`"
+    add_replacement "###IDEA_DIR###" "`cygpath -am $IDEA_OUTPUT`"
+    if [ "x$JT_HOME" = "x" ]; then
+      add_replacement "###JTREG_HOME###" ""
+    else
+      add_replacement "###JTREG_HOME###" "`cygpath -am $JT_HOME`"
+    fi
+fi
 
 SOURCE_PREFIX="<sourceFolder url=\"file://"
 SOURCE_POSTFIX="\" isTestSource=\"false\" />"
 
 for root in $MODULE_ROOTS; do
+    if [ "x$CYGPATH" != "x" ]; then
+    	root=`cygpath -am $root`
+    fi
     SOURCES=$SOURCES" $SOURCE_PREFIX""$root""$SOURCE_POSTFIX"
 done
 
--- a/make/autoconf/version-numbers	Mon Nov 12 12:39:03 2018 +0530
+++ b/make/autoconf/version-numbers	Wed Nov 14 17:16:44 2018 +0530
@@ -35,7 +35,7 @@
 DEFAULT_VERSION_DATE=2019-03-19
 DEFAULT_VERSION_CLASSFILE_MAJOR=56  # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`"
 DEFAULT_VERSION_CLASSFILE_MINOR=0
-DEFAULT_ACCEPTABLE_BOOT_VERSIONS="10 11 12"
+DEFAULT_ACCEPTABLE_BOOT_VERSIONS="11 12"
 
 LAUNCHER_NAME=openjdk
 PRODUCT_NAME=OpenJDK
--- a/make/conf/jib-profiles.js	Mon Nov 12 12:39:03 2018 +0530
+++ b/make/conf/jib-profiles.js	Wed Nov 14 17:16:44 2018 +0530
@@ -361,7 +361,7 @@
         };
     };
 
-    common.boot_jdk_version = "10";
+    common.boot_jdk_version = "11";
     common.boot_jdk_home = input.get("boot_jdk", "home_path") + "/jdk-"
         + common.boot_jdk_version
         + (input.build_os == "macosx" ? ".jdk/Contents/Home" : "");
@@ -851,9 +851,10 @@
             server: "jpg",
             product: "jdk",
             version: common.boot_jdk_version,
-            build_number: "46",
+            build_number: "28",
             file: "bundles/" + boot_jdk_platform + "/jdk-" + common.boot_jdk_version + "_"
-                + boot_jdk_platform + "_bin.tar.gz",
+                + boot_jdk_platform + "_bin"
+		+ (input.build_os == "windows" ? ".zip" : ".tar.gz"),
             configure_args: "--with-boot-jdk=" + common.boot_jdk_home,
             environment_path: common.boot_jdk_home + "/bin"
         },
--- a/make/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/Main.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/make/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/Main.java	Wed Nov 14 17:16:44 2018 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2018, 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
@@ -43,7 +43,7 @@
     /**
      * ASM version to be used by nasgen tool.
      */
-    public static final int ASM_VERSION = Opcodes.ASM5;
+    public static final int ASM_VERSION = Opcodes.ASM7;
 
     private static final boolean DEBUG = Boolean.getBoolean("nasgen.debug");
 
--- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -1902,8 +1902,8 @@
     Label L_done;
 
     __ ldrb(rscratch1, Address(rbcp, 0));
-    __ cmpw(r1, Bytecodes::_invokestatic);
-    __ br(Assembler::EQ, L_done);
+    __ cmpw(rscratch1, Bytecodes::_invokestatic);
+    __ br(Assembler::NE, L_done);
 
     // The member name argument must be restored if _invokestatic is re-executed after a PopFrame call.
     // Detect such a case in the InterpreterRuntime function and return the member name argument, or NULL.
@@ -1938,7 +1938,6 @@
   // remove the activation (without doing throws on illegalMonitorExceptions)
   __ remove_activation(vtos, false, true, false);
   // restore exception
-  // restore exception
   __ get_vm_result(r0, rthread);
 
   // In between activations - previous activation type unknown yet
@@ -1947,9 +1946,8 @@
   //
   // r0: exception
   // lr: return address/pc that threw exception
-  // rsp: expression stack of caller
+  // esp: expression stack of caller
   // rfp: fp of caller
-  // FIXME: There's no point saving LR here because VM calls don't trash it
   __ stp(r0, lr, Address(__ pre(sp, -2 * wordSize)));  // save exception & return address
   __ super_call_VM_leaf(CAST_FROM_FN_PTR(address,
                           SharedRuntime::exception_handler_for_return_address),
--- a/src/hotspot/cpu/arm/assembler_arm_32.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/cpu/arm/assembler_arm_32.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -498,7 +498,7 @@
   void dmb(DMB_Opt opt, Register reg) {
     if (VM_Version::arm_arch() >= 7) {
       emit_int32(0xF57FF050 | opt);
-    } else {
+    } else if (VM_Version::arm_arch() == 6) {
       bool preserve_tmp = (reg == noreg);
       if(preserve_tmp) {
         reg = Rtemp;
--- a/src/hotspot/os/aix/os_aix.inline.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/os/aix/os_aix.inline.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -41,10 +41,6 @@
   return strncmp(s1, s2, num);
 }
 
-inline bool os::obsolete_option(const JavaVMOption *option) {
-  return false;
-}
-
 inline bool os::uses_stack_guard_pages() {
   return true;
 }
--- a/src/hotspot/os/bsd/os_bsd.inline.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/os/bsd/os_bsd.inline.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -39,10 +39,6 @@
   return strncmp(s1, s2, num);
 }
 
-inline bool os::obsolete_option(const JavaVMOption *option) {
-  return false;
-}
-
 inline bool os::uses_stack_guard_pages() {
   return true;
 }
--- a/src/hotspot/os/linux/os_linux.inline.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/os/linux/os_linux.inline.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -39,10 +39,6 @@
   return strncmp(s1, s2, num);
 }
 
-inline bool os::obsolete_option(const JavaVMOption *option) {
-  return false;
-}
-
 inline bool os::uses_stack_guard_pages() {
   return true;
 }
--- a/src/hotspot/os/solaris/os_solaris.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/os/solaris/os_solaris.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -700,19 +700,6 @@
   BREAKPOINT;
 }
 
-bool os::obsolete_option(const JavaVMOption *option) {
-  if (!strncmp(option->optionString, "-Xt", 3)) {
-    return true;
-  } else if (!strncmp(option->optionString, "-Xtm", 4)) {
-    return true;
-  } else if (!strncmp(option->optionString, "-Xverifyheap", 12)) {
-    return true;
-  } else if (!strncmp(option->optionString, "-Xmaxjitcodesize", 16)) {
-    return true;
-  }
-  return false;
-}
-
 bool os::Solaris::valid_stack_address(Thread* thread, address sp) {
   address  stackStart  = (address)thread->stack_base();
   address  stackEnd    = (address)(stackStart - (address)thread->stack_size());
--- a/src/hotspot/os/windows/os_windows.inline.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/os/windows/os_windows.inline.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -45,10 +45,6 @@
   return (void*)::GetProcAddress((HMODULE)lib, name);
 }
 
-inline bool os::obsolete_option(const JavaVMOption *option) {
-  return false;
-}
-
 inline bool os::uses_stack_guard_pages() {
   return true;
 }
--- a/src/hotspot/os_cpu/linux_arm/orderAccess_linux_arm.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/os_cpu/linux_arm/orderAccess_linux_arm.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -63,7 +63,7 @@
      __asm__ volatile (
      ".word 0xF57FF050 | 0xf" : : : "memory");
 #endif
-   } else {
+   } else if (VM_Version::arm_arch() == 6) {
      intptr_t zero = 0;
      __asm__ volatile (
        "mcr p15, 0, %0, c7, c10, 5"
@@ -80,7 +80,7 @@
      __asm__ volatile (
      ".word 0xF57FF050 | 0xe" : : : "memory");
 #endif
-   } else {
+   } else if (VM_Version::arm_arch() == 6) {
      intptr_t zero = 0;
      __asm__ volatile (
        "mcr p15, 0, %0, c7, c10, 5"
--- a/src/hotspot/share/classfile/classListParser.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/classfile/classListParser.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -287,7 +287,7 @@
   if (!is_id_specified()) {
     error("If source location is specified, id must be also specified");
   }
-  InstanceKlass* k = ClassLoaderExt::load_class(class_name, _source, THREAD);
+  InstanceKlass* k = ClassLoaderExt::load_class(class_name, _source, CHECK_NULL);
 
   if (strncmp(_class_name, "java/", 5) == 0) {
     log_info(cds)("Prohibited package for non-bootstrap classes: %s.class from %s",
@@ -303,8 +303,9 @@
             _interfaces->length(), k->local_interfaces()->length());
     }
 
-    if (!SystemDictionaryShared::add_non_builtin_klass(class_name, ClassLoaderData::the_null_class_loader_data(),
-                                                       k, THREAD)) {
+    bool added = SystemDictionaryShared::add_unregistered_class(k, CHECK_NULL);
+    if (!added) {
+      // We allow only a single unregistered class for each unique name.
       error("Duplicated class %s", _class_name);
     }
 
@@ -353,7 +354,7 @@
                               vmSymbols::loadClass_name(),
                               vmSymbols::string_class_signature(),
                               ext_class_name,
-                              THREAD);
+                              THREAD); // <-- failure is handled below
     } else {
       // array classes are not supported in class list.
       THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
--- a/src/hotspot/share/classfile/classLoaderDataGraph.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/classfile/classLoaderDataGraph.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -496,11 +496,11 @@
 
 // Move class loader data from main list to the unloaded list for unloading
 // and deallocation later.
-bool ClassLoaderDataGraph::do_unloading(bool do_cleaning) {
+bool ClassLoaderDataGraph::do_unloading() {
   assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
 
   // Indicate whether safepoint cleanup is needed.
-  _safepoint_cleanup_needed |= do_cleaning;
+  _safepoint_cleanup_needed = true;
 
   ClassLoaderData* data = _head;
   ClassLoaderData* prev = NULL;
--- a/src/hotspot/share/classfile/classLoaderDataGraph.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/classfile/classLoaderDataGraph.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -88,7 +88,7 @@
   static void loaded_classes_do(KlassClosure* klass_closure);
   static void unlocked_loaded_classes_do(KlassClosure* klass_closure);
   static void classes_unloading_do(void f(Klass* const));
-  static bool do_unloading(bool do_cleaning);
+  static bool do_unloading();
 
   // Expose state to avoid logging overhead in safepoint cleanup tasks.
   static inline bool should_clean_metaspaces_and_reset();
--- a/src/hotspot/share/classfile/classLoaderExt.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/classfile/classLoaderExt.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -350,7 +350,3 @@
   cached_path_entries->insert_before(0, ccpe);
   return new_entry;
 }
-
-Klass* ClassLoaderExt::load_one_class(ClassListParser* parser, TRAPS) {
-  return parser->load_current_class(THREAD);
-}
--- a/src/hotspot/share/classfile/classLoaderExt.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/classfile/classLoaderExt.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -115,7 +115,6 @@
   static void record_result(const s2 classpath_index,
                             InstanceKlass* result, TRAPS);
   static InstanceKlass* load_class(Symbol* h_name, const char* path, TRAPS);
-  static Klass* load_one_class(ClassListParser* parser, TRAPS);
   static void set_has_app_classes() {
     _has_app_classes = true;
   }
--- a/src/hotspot/share/classfile/compactHashtable.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/classfile/compactHashtable.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -163,6 +163,7 @@
     msg.info("Average bucket size     : %9.3f", summary.avg());
     msg.info("Variance of bucket size : %9.3f", summary.variance());
     msg.info("Std. dev. of bucket size: %9.3f", summary.sd());
+    msg.info("Maximum bucket size     : %9d", (int)summary.maximum());
     msg.info("Empty buckets           : %9d", _num_empty_buckets);
     msg.info("Value_Only buckets      : %9d", _num_value_only_buckets);
     msg.info("Other buckets           : %9d", _num_other_buckets);
--- a/src/hotspot/share/classfile/compactHashtable.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/classfile/compactHashtable.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -244,8 +244,6 @@
   }
 
 public:
-  CompactHashtable() : SimpleCompactHashtable() {}
-
   // Lookup a value V from the compact table using key K
   inline V lookup(K key, unsigned int hash, int len) const {
     if (_entry_count > 0) {
@@ -299,10 +297,55 @@
       }
     }
   }
+
+  void print_table_statistics(outputStream* st, const char* name) {
+    st->print_cr("%s statistics:", name);
+    int total_entries = 0;
+    int max_bucket = 0;
+    for (u4 i = 0; i < _bucket_count; i++) {
+      u4 bucket_info = _buckets[i];
+      int bucket_type = BUCKET_TYPE(bucket_info);
+      int bucket_size;
+
+      if (bucket_type == VALUE_ONLY_BUCKET_TYPE) {
+        bucket_size = 1;
+      } else {
+        bucket_size = (BUCKET_OFFSET(_buckets[i + 1]) - BUCKET_OFFSET(bucket_info)) / 2;
+      }
+      total_entries += bucket_size;
+      if (max_bucket < bucket_size) {
+        max_bucket = bucket_size;
+      }
+    }
+    st->print_cr("Number of buckets       : %9d", _bucket_count);
+    st->print_cr("Number of entries       : %9d", total_entries);
+    st->print_cr("Maximum bucket size     : %9d", max_bucket);
+  }
 };
 
 ////////////////////////////////////////////////////////////////////////
 //
+// OffsetCompactHashtable -- This is used to store many types of objects
+// in the CDS archive. On 64-bit platforms, we save space by using a 32-bit
+// offset from the CDS base address.
+
+template <typename V>
+V read_value_from_compact_hashtable(address base_address, u4 offset) {
+  return (V)(base_address + offset);
+}
+
+template <
+  typename K,
+  typename V,
+  bool (*EQUALS)(V value, K key, int len)
+  >
+class OffsetCompactHashtable : public CompactHashtable<
+    K, V, read_value_from_compact_hashtable<V>, EQUALS> {
+};
+
+
+////////////////////////////////////////////////////////////////////////
+//
 // Read/Write the contents of a hashtable textual dump (created by
 // SymbolTable::dump and StringTable::dump).
 // Because the dump file may be big (hundred of MB in extreme cases),
--- a/src/hotspot/share/classfile/dictionary.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/classfile/dictionary.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -27,7 +27,6 @@
 #include "classfile/dictionary.inline.hpp"
 #include "classfile/protectionDomainCache.hpp"
 #include "classfile/systemDictionary.hpp"
-#include "classfile/systemDictionaryShared.hpp"
 #include "logging/log.hpp"
 #include "logging/logStream.hpp"
 #include "memory/iterator.hpp"
@@ -44,16 +43,8 @@
 // needs resizing, which is costly to do at Safepoint.
 bool Dictionary::_some_dictionary_needs_resizing = false;
 
-size_t Dictionary::entry_size() {
-  if (DumpSharedSpaces) {
-    return SystemDictionaryShared::dictionary_entry_size();
-  } else {
-    return sizeof(DictionaryEntry);
-  }
-}
-
 Dictionary::Dictionary(ClassLoaderData* loader_data, int table_size, bool resizable)
-  : Hashtable<InstanceKlass*, mtClass>(table_size, (int)entry_size()),
+  : Hashtable<InstanceKlass*, mtClass>(table_size, (int)sizeof(DictionaryEntry)),
     _resizable(resizable), _needs_resizing(false), _loader_data(loader_data) {
 };
 
@@ -61,7 +52,7 @@
 Dictionary::Dictionary(ClassLoaderData* loader_data,
                        int table_size, HashtableBucket<mtClass>* t,
                        int number_of_entries, bool resizable)
-  : Hashtable<InstanceKlass*, mtClass>(table_size, (int)entry_size(), t, number_of_entries),
+  : Hashtable<InstanceKlass*, mtClass>(table_size, (int)sizeof(DictionaryEntry), t, number_of_entries),
     _resizable(resizable), _needs_resizing(false), _loader_data(loader_data) {
 };
 
@@ -83,9 +74,6 @@
   DictionaryEntry* entry = (DictionaryEntry*)Hashtable<InstanceKlass*, mtClass>::allocate_new_entry(hash, klass);
   entry->set_pd_set(NULL);
   assert(klass->is_instance_klass(), "Must be");
-  if (DumpSharedSpaces) {
-    SystemDictionaryShared::init_shared_dictionary_entry(klass, entry);
-  }
   return entry;
 }
 
@@ -280,26 +268,6 @@
   }
 }
 
-void Dictionary::remove_classes_in_error_state() {
-  assert(DumpSharedSpaces, "supported only when dumping");
-  DictionaryEntry* probe = NULL;
-  for (int index = 0; index < table_size(); index++) {
-    for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) {
-      probe = *p;
-      InstanceKlass* ik = probe->instance_klass();
-      if (ik->is_in_error_state()) { // purge this entry
-        *p = probe->next();
-        free_entry(probe);
-        ResourceMark rm;
-        tty->print_cr("Preload Warning: Removed error class: %s", ik->external_name());
-        continue;
-      }
-
-      p = probe->next_addr();
-    }
-  }
-}
-
 //   Just the classes from defining class loaders
 void Dictionary::classes_do(void f(InstanceKlass*)) {
   for (int index = 0; index < table_size(); index++) {
@@ -349,7 +317,6 @@
                           probe != NULL;
                           probe = probe->next()) {
       it->push(probe->klass_addr());
-      ((SharedDictionaryEntry*)probe)->metaspace_pointers_do(it);
     }
   }
 }
@@ -390,9 +357,7 @@
                         entry != NULL;
                         entry = entry->next()) {
     if (entry->hash() == hash && entry->equals(class_name)) {
-      if (!DumpSharedSpaces || SystemDictionaryShared::is_builtin(entry)) {
-        return entry;
-      }
+      return entry;
     }
   }
   return NULL;
@@ -423,18 +388,6 @@
 }
 
 
-// Variant of find_class for shared classes.  No locking required, as
-// that table is static.
-
-InstanceKlass* Dictionary::find_shared_class(int index, unsigned int hash,
-                                             Symbol* name) {
-  assert (index == index_for(name), "incorrect index?");
-
-  DictionaryEntry* entry = get_entry(index, hash, name);
-  return (entry != NULL) ? entry->instance_klass() : NULL;
-}
-
-
 void Dictionary::add_protection_domain(int index, unsigned int hash,
                                        InstanceKlass* klass,
                                        Handle protection_domain,
@@ -465,70 +418,6 @@
   return entry->is_valid_protection_domain(protection_domain);
 }
 
-#if INCLUDE_CDS
-static bool is_jfr_event_class(Klass *k) {
-  while (k) {
-    if (k->name()->equals("jdk/internal/event/Event")) {
-      return true;
-    }
-    k = k->super();
-  }
-  return false;
-}
-
-void Dictionary::reorder_dictionary_for_sharing() {
-
-  // Copy all the dictionary entries into a single master list.
-  assert(DumpSharedSpaces, "Should only be used at dump time");
-
-  DictionaryEntry* master_list = NULL;
-  for (int i = 0; i < table_size(); ++i) {
-    DictionaryEntry* p = bucket(i);
-    while (p != NULL) {
-      DictionaryEntry* next = p->next();
-      InstanceKlass*ik = p->instance_klass();
-      if (ik->has_signer_and_not_archived()) {
-        // We cannot include signed classes in the archive because the certificates
-        // used during dump time may be different than those used during
-        // runtime (due to expiration, etc).
-        ResourceMark rm;
-        tty->print_cr("Preload Warning: Skipping %s from signed JAR",
-                       ik->name()->as_C_string());
-        free_entry(p);
-      } else if (is_jfr_event_class(ik)) {
-        // We cannot include JFR event classes because they need runtime-specific
-        // instrumentation in order to work with -XX:FlightRecorderOptions=retransform=false.
-        // There are only a small number of these classes, so it's not worthwhile to
-        // support them and make CDS more complicated.
-        ResourceMark rm;
-        tty->print_cr("Skipping JFR event class %s", ik->name()->as_C_string());
-        free_entry(p);
-      } else {
-        p->set_next(master_list);
-        master_list = p;
-      }
-      p = next;
-    }
-    set_entry(i, NULL);
-  }
-
-  // Add the dictionary entries back to the list in the correct buckets.
-  while (master_list != NULL) {
-    DictionaryEntry* p = master_list;
-    master_list = master_list->next();
-    p->set_next(NULL);
-    Symbol* class_name = p->instance_klass()->name();
-    // Since the null class loader data isn't copied to the CDS archive,
-    // compute the hash with NULL for loader data.
-    unsigned int hash = compute_hash(class_name);
-    int index = hash_to_index(hash);
-    p->set_hash(hash);
-    p->set_next(bucket(index));
-    set_entry(index, p);
-  }
-}
-#endif
-
 SymbolPropertyTable::SymbolPropertyTable(int table_size)
   : Hashtable<Symbol*, mtSymbol>(table_size, sizeof(SymbolPropertyEntry))
 {
@@ -605,10 +494,7 @@
          (loader_data() == e->class_loader_data());
       st->print("%4d: %s%s", index, is_defining_class ? " " : "^", e->external_name());
       ClassLoaderData* cld = e->class_loader_data();
-      if (cld == NULL) {
-        // Shared class not restored yet in shared dictionary
-        st->print(", loader data <shared, not restored>");
-      } else if (!loader_data()->is_the_null_class_loader_data()) {
+      if (!loader_data()->is_the_null_class_loader_data()) {
         // Class loader output for the dictionary for the null class loader data is
         // redundant and obvious.
         st->print(", ");
@@ -634,7 +520,7 @@
   ClassLoaderData* cld = loader_data();
   // class loader must be present;  a null class loader is the
   // boostrap loader
-  guarantee(cld != NULL || DumpSharedSpaces ||
+  guarantee(cld != NULL ||
             cld->class_loader() == NULL ||
             cld->class_loader()->is_instance(),
             "checking type of class_loader");
--- a/src/hotspot/share/classfile/dictionary.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/classfile/dictionary.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -36,8 +36,7 @@
 class BoolObjectClosure;
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// The data structure for the class loader data dictionaries (and the shared system
-// dictionary).
+// The data structure for the class loader data dictionaries.
 
 class Dictionary : public Hashtable<InstanceKlass*, mtClass> {
   friend class VMStructs;
@@ -54,8 +53,6 @@
 
   void clean_cached_protection_domains(DictionaryEntry* probe);
 
-protected:
-  static size_t entry_size();
 public:
   Dictionary(ClassLoaderData* loader_data, int table_size, bool resizable = false);
   Dictionary(ClassLoaderData* loader_data, int table_size, HashtableBucket<mtClass>* t, int number_of_entries, bool resizable = false);
@@ -70,15 +67,12 @@
 
   InstanceKlass* find_class(int index, unsigned int hash, Symbol* name);
 
-  InstanceKlass* find_shared_class(int index, unsigned int hash, Symbol* name);
-
   void classes_do(void f(InstanceKlass*));
   void classes_do(void f(InstanceKlass*, TRAPS), TRAPS);
   void all_entries_do(KlassClosure* closure);
   void classes_do(MetaspaceClosure* it);
 
   void unlink();
-  void remove_classes_in_error_state();
 
   // Unload classes whose defining loaders are unloaded
   void do_unloading();
@@ -92,9 +86,6 @@
                              InstanceKlass* klass,
                              Handle protection_domain, TRAPS);
 
-  // Sharing support
-  void reorder_dictionary_for_sharing() NOT_CDS_RETURN;
-
   void print_on(outputStream* st) const;
   void verify();
   DictionaryEntry* bucket(int i) const {
--- a/src/hotspot/share/classfile/javaClasses.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/classfile/javaClasses.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -1090,8 +1090,7 @@
 
   if (k->is_instance_klass()) {
     InstanceKlass *ik = InstanceKlass::cast(k);
-    assert(ik->signers() == NULL && !k->has_signer_and_not_archived(),
-           "class with signer cannot be supported");
+    assert(ik->signers() == NULL, "class with signer should have been excluded");
 
     if (!(ik->is_shared_boot_class() || ik->is_shared_platform_class() ||
           ik->is_shared_app_class())) {
--- a/src/hotspot/share/classfile/stringTable.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/classfile/stringTable.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -847,7 +847,7 @@
   assert(HeapShared::is_heap_object_archiving_allowed(), "must be");
 
   CopyToArchive copy(writer);
-  StringTable::the_table()->_local_table->do_scan(Thread::current(), copy);
+  StringTable::the_table()->_local_table->do_safepoint_scan(copy);
 }
 
 void StringTable::write_to_archive() {
--- a/src/hotspot/share/classfile/symbolTable.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/classfile/symbolTable.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -57,9 +57,6 @@
 #define ON_STACK_BUFFER_LENGTH 128
 
 // --------------------------------------------------------------------------
-inline Symbol* read_symbol_from_compact_hashtable(address base_address, u4 offset) {
-  return (Symbol*)(base_address + offset);
-}
 
 inline bool symbol_equals_compact_hashtable_entry(Symbol* value, const char* key, int len) {
   if (value->equals(key, len)) {
@@ -70,9 +67,8 @@
   }
 }
 
-static CompactHashtable<
+static OffsetCompactHashtable<
   const char*, Symbol*,
-  read_symbol_from_compact_hashtable,
   symbol_equals_compact_hashtable_entry
 > _shared_table;
 
@@ -281,7 +277,7 @@
 void SymbolTable::metaspace_pointers_do(MetaspaceClosure* it) {
   assert(DumpSharedSpaces, "called only during dump time");
   MetaspacePointersDo mpd(it);
-  SymbolTable::the_table()->_local_table->do_scan(Thread::current(), mpd);
+  SymbolTable::the_table()->_local_table->do_safepoint_scan(mpd);
 }
 
 Symbol* SymbolTable::lookup_dynamic(const char* name,
@@ -637,23 +633,14 @@
     unsigned int fixed_hash = hash_shared_symbol((const char*)sym->bytes(), sym->utf8_length());
     assert(fixed_hash == hash_symbol((const char*)sym->bytes(), sym->utf8_length(), false),
            "must not rehash during dumping");
-
-    uintx deltax = MetaspaceShared::object_delta(sym);
-    // When the symbols are stored into the archive, we already check that
-    // they won't be more than MAX_SHARED_DELTA from the base address, or
-    // else the dumping would have been aborted.
-    assert(deltax <= MAX_SHARED_DELTA, "must not be");
-    u4 delta = u4(deltax);
-
-    // add to the compact table
-    _writer->add(fixed_hash, delta);
+    _writer->add(fixed_hash, MetaspaceShared::object_delta_u4(sym));
     return true;
   }
 };
 
 void SymbolTable::copy_shared_symbol_table(CompactHashtableWriter* writer) {
   CopyToArchive copy(writer);
-  SymbolTable::the_table()->_local_table->do_scan(Thread::current(), copy);
+  SymbolTable::the_table()->_local_table->do_safepoint_scan(copy);
 }
 
 void SymbolTable::write_to_archive() {
--- a/src/hotspot/share/classfile/systemDictionary.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/classfile/systemDictionary.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -96,7 +96,6 @@
 #endif
 
 PlaceholderTable*      SystemDictionary::_placeholders        = NULL;
-Dictionary*            SystemDictionary::_shared_dictionary   = NULL;
 LoaderConstraintTable* SystemDictionary::_loader_constraints  = NULL;
 ResolutionErrorTable*  SystemDictionary::_resolution_errors   = NULL;
 SymbolPropertyTable*   SystemDictionary::_invoke_method_table = NULL;
@@ -355,7 +354,7 @@
   assert(!FieldType::is_array(super_name), "invalid super class name");
 #if INCLUDE_CDS
   if (DumpSharedSpaces) {
-    // Special processing for CDS dump time.
+    // Special processing for handling UNREGISTERED shared classes.
     InstanceKlass* k = SystemDictionaryShared::dump_time_resolve_super_or_fail(child_name,
         super_name, class_loader, protection_domain, is_superclass, CHECK_NULL);
     if (k) {
@@ -1163,39 +1162,11 @@
 }
 
 #if INCLUDE_CDS
-void SystemDictionary::set_shared_dictionary(HashtableBucket<mtClass>* t, int length,
-                                             int number_of_entries) {
-  assert(!DumpSharedSpaces, "Should not be called with DumpSharedSpaces");
-  assert(length == _shared_dictionary_size * sizeof(HashtableBucket<mtClass>),
-         "bad shared dictionary size.");
-  _shared_dictionary = new Dictionary(ClassLoaderData::the_null_class_loader_data(),
-                                      _shared_dictionary_size, t, number_of_entries,
-                                      false /* explicitly set _resizable to false */);
-}
-
-
-// If there is a shared dictionary, then find the entry for the
-// given shared system class, if any.
-
-InstanceKlass* SystemDictionary::find_shared_class(Symbol* class_name) {
-  if (shared_dictionary() != NULL) {
-    unsigned int d_hash = shared_dictionary()->compute_hash(class_name);
-    int d_index = shared_dictionary()->hash_to_index(d_hash);
-
-    return shared_dictionary()->find_shared_class(d_index, d_hash, class_name);
-  } else {
-    return NULL;
-  }
-}
-
-
-// Load a class for boot loader from the shared spaces (found through
-// the shared system dictionary). Force the super class and all interfaces
-// to be loaded.
+// Load a class for boot loader from the shared spaces. This also
+// forces the super class and all interfaces to be loaded.
 InstanceKlass* SystemDictionary::load_shared_boot_class(Symbol* class_name,
                                                         TRAPS) {
-  InstanceKlass* ik = find_shared_class(class_name);
-  // Make sure we only return the boot class.
+  InstanceKlass* ik = SystemDictionaryShared::find_builtin_class(class_name);
   if (ik != NULL && ik->is_shared_boot_class()) {
     return load_shared_class(ik, Handle(), Handle(), THREAD);
   }
@@ -1410,18 +1381,6 @@
   }
   return ik;
 }
-
-void SystemDictionary::clear_invoke_method_table() {
-  SymbolPropertyEntry* spe = NULL;
-  for (int index = 0; index < _invoke_method_table->table_size(); index++) {
-    SymbolPropertyEntry* p = _invoke_method_table->bucket(index);
-    while (p != NULL) {
-      spe = p;
-      p = p->next();
-      _invoke_method_table->free_entry(spe);
-    }
-  }
-}
 #endif // INCLUDE_CDS
 
 InstanceKlass* SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) {
@@ -1845,15 +1804,14 @@
 
 // Assumes classes in the SystemDictionary are only unloaded at a safepoint
 // Note: anonymous classes are not in the SD.
-bool SystemDictionary::do_unloading(GCTimer* gc_timer,
-                                    bool do_cleaning) {
+bool SystemDictionary::do_unloading(GCTimer* gc_timer) {
 
   bool unloading_occurred;
   {
     GCTraceTime(Debug, gc, phases) t("ClassLoaderData", gc_timer);
 
     // First, mark for unload all ClassLoaderData referencing a dead class loader.
-    unloading_occurred = ClassLoaderDataGraph::do_unloading(do_cleaning);
+    unloading_occurred = ClassLoaderDataGraph::do_unloading();
     if (unloading_occurred) {
       JFR_ONLY(Jfr::on_unloading_classes();)
       ClassLoaderDataGraph::clean_module_and_package_info();
@@ -1883,7 +1841,7 @@
     _pd_cache_table->trigger_cleanup();
   }
 
-  if (do_cleaning) {
+  {
     GCTraceTime(Debug, gc, phases) t("ResolvedMethodTable", gc_timer);
     ResolvedMethodTable::trigger_cleanup();
   }
@@ -1901,11 +1859,6 @@
   invoke_method_table()->oops_do(f);
 }
 
-// CDS: scan and relocate all classes in the system dictionary.
-void SystemDictionary::classes_do(MetaspaceClosure* it) {
-  ClassLoaderData::the_null_class_loader_data()->dictionary()->classes_do(it);
-}
-
 // CDS: scan and relocate all classes referenced by _well_known_klasses[].
 void SystemDictionary::well_known_klasses_do(MetaspaceClosure* it) {
   for (int id = FIRST_WKID; id < WKID_LIMIT; id++) {
@@ -1921,22 +1874,6 @@
   invoke_method_table()->methods_do(f);
 }
 
-class RemoveClassesClosure : public CLDClosure {
-  public:
-    void do_cld(ClassLoaderData* cld) {
-      if (cld->is_system_class_loader_data() || cld->is_platform_class_loader_data()) {
-        cld->dictionary()->remove_classes_in_error_state();
-      }
-    }
-};
-
-void SystemDictionary::remove_classes_in_error_state() {
-  ClassLoaderData::the_null_class_loader_data()->dictionary()->remove_classes_in_error_state();
-  RemoveClassesClosure rcc;
-  MutexLocker ml(ClassLoaderDataGraph_lock);
-  ClassLoaderDataGraph::cld_do(&rcc);
-}
-
 // ----------------------------------------------------------------------------
 // Initialization
 
@@ -2039,6 +1976,7 @@
     HeapShared::fixup_mapped_heap_regions();
 
     // Initialize the constant pool for the Object_class
+    assert(Object_klass()->is_shared(), "must be");
     Object_klass()->constants()->restore_unshareable_info(CHECK);
     resolve_wk_klasses_through(WK_KLASS_ENUM_NAME(Class_klass), scan, CHECK);
   } else
@@ -2922,40 +2860,10 @@
   return _pd_cache_table->get(protection_domain);
 }
 
-#if INCLUDE_CDS
-void SystemDictionary::reorder_dictionary_for_sharing() {
-  ClassLoaderData::the_null_class_loader_data()->dictionary()->reorder_dictionary_for_sharing();
-}
-#endif
-
-size_t SystemDictionary::count_bytes_for_buckets() {
-  return ClassLoaderData::the_null_class_loader_data()->dictionary()->count_bytes_for_buckets();
-}
-
-size_t SystemDictionary::count_bytes_for_table() {
-  return ClassLoaderData::the_null_class_loader_data()->dictionary()->count_bytes_for_table();
-}
-
-void SystemDictionary::copy_buckets(char* top, char* end) {
-  ClassLoaderData::the_null_class_loader_data()->dictionary()->copy_buckets(top, end);
-}
-
-void SystemDictionary::copy_table(char* top, char* end) {
-  ClassLoaderData::the_null_class_loader_data()->dictionary()->copy_table(top, end);
-}
-
 // ----------------------------------------------------------------------------
-void SystemDictionary::print_shared(outputStream *st) {
-  shared_dictionary()->print_on(st);
-}
 
 void SystemDictionary::print_on(outputStream *st) {
-  if (shared_dictionary() != NULL) {
-    st->print_cr("Shared Dictionary");
-    shared_dictionary()->print_on(st);
-    st->cr();
-  }
-
+  CDS_ONLY(SystemDictionaryShared::print_on(st));
   GCMutexLocker mu(SystemDictionary_lock);
 
   ClassLoaderDataGraph::print_dictionary(st);
@@ -2997,9 +2905,7 @@
   if (verbose) {
     print_on(st);
   } else {
-    if (shared_dictionary() != NULL) {
-      shared_dictionary()->print_table_statistics(st, "Shared Dictionary");
-    }
+    CDS_ONLY(SystemDictionaryShared::print_table_statistics(st));
     ClassLoaderDataGraph::print_dictionary_statistics(st);
     placeholders()->print_table_statistics(st, "Placeholder Table");
     constraints()->print_table_statistics(st, "LoaderConstraints Table");
@@ -3032,60 +2938,6 @@
   }
 }
 
-class CombineDictionariesClosure : public CLDClosure {
-  private:
-    Dictionary* _master_dictionary;
-  public:
-    CombineDictionariesClosure(Dictionary* master_dictionary) :
-      _master_dictionary(master_dictionary) {}
-    void do_cld(ClassLoaderData* cld) {
-      ResourceMark rm;
-      if (cld->is_unsafe_anonymous()) {
-        return;
-      }
-      if (cld->is_system_class_loader_data() || cld->is_platform_class_loader_data()) {
-        for (int i = 0; i < cld->dictionary()->table_size(); ++i) {
-          Dictionary* curr_dictionary = cld->dictionary();
-          DictionaryEntry* p = curr_dictionary->bucket(i);
-          while (p != NULL) {
-            Symbol* name = p->instance_klass()->name();
-            unsigned int d_hash = _master_dictionary->compute_hash(name);
-            int d_index = _master_dictionary->hash_to_index(d_hash);
-            DictionaryEntry* next = p->next();
-            if (p->literal()->class_loader_data() != cld) {
-              // This is an initiating class loader entry; don't use it
-              log_trace(cds)("Skipping initiating cl entry: %s", name->as_C_string());
-              curr_dictionary->free_entry(p);
-            } else {
-              log_trace(cds)("Moved to boot dictionary: %s", name->as_C_string());
-              curr_dictionary->unlink_entry(p);
-              p->set_pd_set(NULL); // pd_set is runtime only information and will be reconstructed.
-              _master_dictionary->add_entry(d_index, p);
-            }
-            p = next;
-          }
-          *curr_dictionary->bucket_addr(i) = NULL;
-        }
-      }
-    }
-};
-
-// Combining platform and system loader dictionaries into boot loader dictionary.
-// During run time, we only have one shared dictionary.
-void SystemDictionary::combine_shared_dictionaries() {
-  assert(DumpSharedSpaces, "dump time only");
-  Dictionary* master_dictionary = ClassLoaderData::the_null_class_loader_data()->dictionary();
-  CombineDictionariesClosure cdc(master_dictionary);
-  ClassLoaderDataGraph::cld_do(&cdc);
-
-  // These tables are no longer valid or necessary. Keeping them around will
-  // cause SystemDictionary::verify() to fail. Let's empty them.
-  _placeholders        = new PlaceholderTable(_placeholder_table_size);
-  _loader_constraints  = new LoaderConstraintTable(_loader_constraint_size);
-
-  NOT_PRODUCT(SystemDictionary::verify());
-}
-
 void SystemDictionary::initialize_oop_storage() {
   _vm_weak_oop_storage =
     new OopStorage("VM Weak Oop Handles",
--- a/src/hotspot/share/classfile/systemDictionary.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/classfile/systemDictionary.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -347,13 +347,7 @@
 
   // Unload (that is, break root links to) all unmarked classes and
   // loaders.  Returns "true" iff something was unloaded.
-  static bool do_unloading(GCTimer* gc_timer,
-                           bool do_cleaning = true);
-
-  // Used by DumpSharedSpaces only to remove classes that failed verification
-  static void remove_classes_in_error_state();
-
-  static int calculate_systemdictionary_size(int loadedclasses);
+  static bool do_unloading(GCTimer* gc_timer);
 
   // Applies "f->do_oop" to all root oops in the system dictionary.
   static void oops_do(OopClosure* f);
@@ -365,19 +359,9 @@
   static ProtectionDomainCacheTable* pd_cache_table() { return _pd_cache_table; }
 
 public:
-  // Sharing support.
-  static void reorder_dictionary_for_sharing() NOT_CDS_RETURN;
-  static void combine_shared_dictionaries();
-  static size_t count_bytes_for_buckets();
-  static size_t count_bytes_for_table();
-  static void copy_buckets(char* top, char* end);
-  static void copy_table(char* top, char* end);
-  static void set_shared_dictionary(HashtableBucket<mtClass>* t, int length,
-                                    int number_of_entries);
   // Printing
   static void print() { return print_on(tty); }
   static void print_on(outputStream* st);
-  static void print_shared(outputStream* st);
   static void dump(outputStream* st, bool verbose);
 
   // Monotonically increasing counter which grows as classes are
@@ -580,7 +564,6 @@
     _loader_constraint_size = 107,                     // number of entries in constraint table
     _resolution_error_size  = 107,                     // number of entries in resolution error table
     _invoke_method_size     = 139,                     // number of entries in invoke method table
-    _shared_dictionary_size = 1009,                    // number of entries in shared dictionary
     _placeholder_table_size = 1009                     // number of entries in hash table for placeholders
   };
 
@@ -590,9 +573,6 @@
   // Hashtable holding placeholders for classes being loaded.
   static PlaceholderTable*       _placeholders;
 
-  // Hashtable holding classes from the shared archive.
-  static Dictionary*             _shared_dictionary;
-
   // Monotonically increasing counter which grows with
   // loading classes as well as hot-swapping and breakpoint setting
   // and removal.
@@ -623,7 +603,6 @@
 
   friend class VM_PopulateDumpSharedSpace;
   friend class TraversePlaceholdersClosure;
-  static Dictionary*         shared_dictionary() { return _shared_dictionary; }
   static PlaceholderTable*   placeholders() { return _placeholders; }
   static LoaderConstraintTable* constraints() { return _loader_constraints; }
   static ResolutionErrorTable* resolution_errors() { return _resolution_errors; }
@@ -663,7 +642,6 @@
 public:
   static bool is_system_class_loader(oop class_loader);
   static bool is_platform_class_loader(oop class_loader);
-  static void clear_invoke_method_table();
 
   // Returns TRUE if the method is a non-public member of class java.lang.Object.
   static bool is_nonpublic_Object_method(Method* m) {
@@ -675,8 +653,6 @@
   static OopStorage* vm_weak_oop_storage();
 
 protected:
-  static InstanceKlass* find_shared_class(Symbol* class_name);
-
   // Setup link to hierarchy
   static void add_to_hierarchy(InstanceKlass* k, TRAPS);
 
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -53,12 +53,277 @@
 #include "runtime/javaCalls.hpp"
 #include "runtime/mutexLocker.hpp"
 #include "utilities/hashtable.inline.hpp"
+#include "utilities/resourceHash.hpp"
 #include "utilities/stringUtils.hpp"
 
 
 objArrayOop SystemDictionaryShared::_shared_protection_domains  =  NULL;
 objArrayOop SystemDictionaryShared::_shared_jar_urls            =  NULL;
 objArrayOop SystemDictionaryShared::_shared_jar_manifests       =  NULL;
+DEBUG_ONLY(bool SystemDictionaryShared::_checked_excluded_classes = false;)
+
+class DumpTimeSharedClassInfo: public CHeapObj<mtClass> {
+public:
+  struct DTConstraint {
+    Symbol* _name;
+    Symbol* _from_name;
+    DTConstraint() : _name(NULL), _from_name(NULL) {}
+    DTConstraint(Symbol* n, Symbol* fn) : _name(n), _from_name(fn) {}
+  };
+
+  InstanceKlass*               _klass;
+  int                          _id;
+  int                          _clsfile_size;
+  int                          _clsfile_crc32;
+  bool                         _excluded;
+  GrowableArray<DTConstraint>* _verifier_constraints;
+  GrowableArray<char>*         _verifier_constraint_flags;
+
+  DumpTimeSharedClassInfo() {
+    _klass = NULL;
+    _id = -1;
+    _clsfile_size = -1;
+    _clsfile_crc32 = -1;
+    _excluded = false;
+    _verifier_constraints = NULL;
+    _verifier_constraint_flags = NULL;
+  }
+
+  void add_verification_constraint(InstanceKlass* k, Symbol* name,
+         Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object);
+
+  bool is_builtin() {
+    return SystemDictionaryShared::is_builtin(_klass);
+  }
+
+  int num_constraints() {
+    if (_verifier_constraint_flags != NULL) {
+      return _verifier_constraint_flags->length();
+    } else {
+      return 0;
+    }
+  }
+
+  void metaspace_pointers_do(MetaspaceClosure* it) {
+    it->push(&_klass);
+    if (_verifier_constraints != NULL) {
+      for (int i = 0; i < _verifier_constraints->length(); i++) {
+        DTConstraint* cons = _verifier_constraints->adr_at(i);
+        it->push(&cons->_name);
+        it->push(&cons->_from_name);
+      }
+    }
+  }
+};
+
+class DumpTimeSharedClassTable: public ResourceHashtable<
+  InstanceKlass*,
+  DumpTimeSharedClassInfo,
+  primitive_hash<InstanceKlass*>,
+  primitive_equals<InstanceKlass*>,
+  15889, // prime number
+  ResourceObj::C_HEAP>
+{
+  int _builtin_count;
+  int _unregistered_count;
+public:
+  DumpTimeSharedClassInfo* find_or_allocate_info_for(InstanceKlass* k) {
+    DumpTimeSharedClassInfo* p = get(k);
+    if (p == NULL) {
+      assert(!SystemDictionaryShared::checked_excluded_classes(),
+             "no new classes can be added after check_excluded_classes");
+      put(k, DumpTimeSharedClassInfo());
+      p = get(k);
+      assert(p != NULL, "sanity");
+      p->_klass = k;
+    }
+    return p;
+  }
+
+  class CountClassByCategory : StackObj {
+    DumpTimeSharedClassTable* _table;
+  public:
+    CountClassByCategory(DumpTimeSharedClassTable* table) : _table(table) {}
+    bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
+      if (SystemDictionaryShared::is_builtin(k)) {
+        ++ _table->_builtin_count;
+      } else {
+        ++ _table->_unregistered_count;
+      }
+      return true; // keep on iterating
+    }
+  };
+
+  void update_counts() {
+    CountClassByCategory counter(this);
+    iterate(&counter);
+  }
+
+  int count_of(bool is_builtin) const {
+    if (is_builtin) {
+      return _builtin_count;
+    } else {
+      return _unregistered_count;
+    }
+  }
+};
+
+class RunTimeSharedClassInfo {
+public:
+  struct CrcInfo {
+    int _clsfile_size;
+    int _clsfile_crc32;
+  };
+
+  // This is different than  DumpTimeSharedClassInfo::DTConstraint. We use
+  // u4 instead of Symbol* to save space on 64-bit CPU.
+  struct RTConstraint {
+    u4 _name;
+    u4 _from_name;
+  };
+
+  InstanceKlass* _klass;
+  int _num_constraints;
+
+  // optional CrcInfo      _crc;  (only for UNREGISTERED classes)
+  // optional RTConstraint _verifier_constraints[_num_constraints]
+  // optional char         _verifier_constraint_flags[_num_constraints]
+
+private:
+  static size_t header_size_size() {
+    return sizeof(RunTimeSharedClassInfo);
+  }
+  static size_t crc_size(InstanceKlass* klass) {
+    if (!SystemDictionaryShared::is_builtin(klass)) {
+      return sizeof(CrcInfo);
+    } else {
+      return 0;
+    }
+  }
+  static size_t verifier_constraints_size(int num_constraints) {
+    return sizeof(RTConstraint) * num_constraints;
+  }
+  static size_t verifier_constraint_flags_size(int num_constraints) {
+    return sizeof(char) * num_constraints;
+  }
+
+public:
+  static size_t byte_size(InstanceKlass* klass, int num_constraints) {
+    return header_size_size() +
+           crc_size(klass) +
+           verifier_constraints_size(num_constraints) +
+           verifier_constraint_flags_size(num_constraints);
+  }
+
+private:
+  size_t crc_offset() const {
+    return header_size_size();
+  }
+  size_t verifier_constraints_offset() const {
+    return crc_offset() + crc_size(_klass);
+  }
+  size_t verifier_constraint_flags_offset() const {
+    return verifier_constraints_offset() + verifier_constraints_size(_num_constraints);
+  }
+
+  void check_constraint_offset(int i) const {
+    assert(0 <= i && i < _num_constraints, "sanity");
+  }
+
+public:
+  CrcInfo* crc() const {
+    assert(crc_size(_klass) > 0, "must be");
+    return (CrcInfo*)(address(this) + crc_offset());
+  }
+  RTConstraint* verifier_constraints() {
+    assert(_num_constraints > 0, "sanity");
+    return (RTConstraint*)(address(this) + verifier_constraints_offset());
+  }
+  RTConstraint* verifier_constraint_at(int i) {
+    check_constraint_offset(i);
+    return verifier_constraints() + i;
+  }
+
+  char* verifier_constraint_flags() {
+    assert(_num_constraints > 0, "sanity");
+    return (char*)(address(this) + verifier_constraint_flags_offset());
+  }
+
+  void init(DumpTimeSharedClassInfo& info) {
+    _klass = info._klass;
+    _num_constraints = info.num_constraints();
+    if (!SystemDictionaryShared::is_builtin(_klass)) {
+      CrcInfo* c = crc();
+      c->_clsfile_size = info._clsfile_size;
+      c->_clsfile_crc32 = info._clsfile_crc32;
+    }
+    if (_num_constraints > 0) {
+      RTConstraint* constraints = verifier_constraints();
+      char* flags = verifier_constraint_flags();
+      int i;
+      for (i = 0; i < _num_constraints; i++) {
+        constraints[i]._name      = MetaspaceShared::object_delta_u4(info._verifier_constraints->at(i)._name);
+        constraints[i]._from_name = MetaspaceShared::object_delta_u4(info._verifier_constraints->at(i)._from_name);
+      }
+      for (i = 0; i < _num_constraints; i++) {
+        flags[i] = info._verifier_constraint_flags->at(i);
+      }
+    }
+  }
+
+  bool matches(int clsfile_size, int clsfile_crc32) const {
+    return crc()->_clsfile_size  == clsfile_size &&
+           crc()->_clsfile_crc32 == clsfile_crc32;
+  }
+
+  Symbol* get_constraint_name(int i) {
+    return (Symbol*)(SharedBaseAddress + verifier_constraint_at(i)->_name);
+  }
+  Symbol* get_constraint_from_name(int i) {
+    return (Symbol*)(SharedBaseAddress + verifier_constraint_at(i)->_from_name);
+  }
+
+  char get_constraint_flag(int i) {
+    check_constraint_offset(i);
+    return verifier_constraint_flags()[i];
+  }
+
+private:
+  // ArchiveCompactor::allocate() has reserved a pointer immediately before
+  // archived InstanceKlasses. We can use this slot to do a quick
+  // lookup of InstanceKlass* -> RunTimeSharedClassInfo* without
+  // building a new hashtable.
+  //
+  //  info_pointer_addr(klass) --> 0x0100   RunTimeSharedClassInfo*
+  //  InstanceKlass* klass     --> 0x0108   <C++ vtbl>
+  //                               0x0110   fields from Klass ...
+  static RunTimeSharedClassInfo** info_pointer_addr(InstanceKlass* klass) {
+    return &((RunTimeSharedClassInfo**)klass)[-1];
+  }
+
+public:
+  static RunTimeSharedClassInfo* get_for(InstanceKlass* klass) {
+    return *info_pointer_addr(klass);
+  }
+  static void set_for(InstanceKlass* klass, RunTimeSharedClassInfo* record) {
+    *info_pointer_addr(klass) = record;
+  }
+
+  // Used by RunTimeSharedDictionary to implement OffsetCompactHashtable::EQUALS
+  static inline bool EQUALS(
+       const RunTimeSharedClassInfo* value, Symbol* key, int len_unused) {
+    return (value->_klass->name() == key);
+  }
+};
+
+class RunTimeSharedDictionary : public OffsetCompactHashtable<
+  Symbol*,
+  const RunTimeSharedClassInfo*,
+  RunTimeSharedClassInfo::EQUALS> {};
+
+static DumpTimeSharedClassTable* _dumptime_table = NULL;
+static RunTimeSharedDictionary _builtin_dictionary;
+static RunTimeSharedDictionary _unregistered_dictionary;
 
 oop SystemDictionaryShared::shared_protection_domain(int index) {
   return _shared_protection_domains->obj_at(index);
@@ -478,9 +743,8 @@
       return NULL;
     }
 
-    if (shared_dictionary() != NULL &&
-        (SystemDictionary::is_system_class_loader(class_loader()) ||
-         SystemDictionary::is_platform_class_loader(class_loader()))) {
+    if (SystemDictionary::is_system_class_loader(class_loader()) ||
+        SystemDictionary::is_platform_class_loader(class_loader())) {
       // Fix for 4474172; see evaluation for more details
       class_loader = Handle(
         THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
@@ -523,8 +787,7 @@
 InstanceKlass* SystemDictionaryShared::load_shared_class_for_builtin_loader(
                  Symbol* class_name, Handle class_loader, TRAPS) {
   assert(UseSharedSpaces, "must be");
-  assert(shared_dictionary() != NULL, "already checked");
-  InstanceKlass* ik = shared_dictionary()->find_class_for_builtin_loader(class_name);
+  InstanceKlass* ik = find_builtin_class(class_name);
 
   if (ik != NULL) {
     if ((ik->is_shared_app_class() &&
@@ -536,7 +799,6 @@
       return load_shared_class(ik, class_loader, protection_domain, THREAD);
     }
   }
-
   return NULL;
 }
 
@@ -574,12 +836,12 @@
 }
 
 // This function is called for loading only UNREGISTERED classes
-InstanceKlass* SystemDictionaryShared::lookup_from_stream(const Symbol* class_name,
+InstanceKlass* SystemDictionaryShared::lookup_from_stream(Symbol* class_name,
                                                           Handle class_loader,
                                                           Handle protection_domain,
                                                           const ClassFileStream* cfs,
                                                           TRAPS) {
-  if (shared_dictionary() == NULL) {
+  if (!UseSharedSpaces) {
     return NULL;
   }
   if (class_name == NULL) {  // don't do this for anonymous classes
@@ -592,27 +854,18 @@
     return NULL;
   }
 
-  ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader());
-  InstanceKlass* k;
-
-  { // UNREGISTERED loader
-    if (!shared_dictionary()->class_exists_for_unregistered_loader(class_name)) {
-      // No classes of this name for unregistered loaders.
-      return NULL;
-    }
-
-    int clsfile_size  = cfs->length();
-    int clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length());
-
-    k = shared_dictionary()->find_class_for_unregistered_loader(class_name,
-                                                                clsfile_size, clsfile_crc32);
-  }
-
-  if (k == NULL) { // not archived
+  const RunTimeSharedClassInfo* record = find_record(&_unregistered_dictionary, class_name);
+  if (record == NULL) {
     return NULL;
   }
 
-  return acquire_class_for_current_thread(k, class_loader,
+  int clsfile_size  = cfs->length();
+  int clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length());
+  if (!record->matches(clsfile_size, clsfile_crc32)) {
+    return NULL;
+  }
+
+  return acquire_class_for_current_thread(record->_klass, class_loader,
                                           protection_domain, THREAD);
 }
 
@@ -649,19 +902,27 @@
   return shared_klass;
 }
 
-bool SystemDictionaryShared::add_non_builtin_klass(Symbol* name,
-                                                   ClassLoaderData* loader_data,
-                                                   InstanceKlass* k,
-                                                   TRAPS) {
+static ResourceHashtable<
+  Symbol*, bool,
+  primitive_hash<Symbol*>,
+  primitive_equals<Symbol*>,
+  6661,                             // prime number
+  ResourceObj::C_HEAP> _loaded_unregistered_classes;
+
+bool SystemDictionaryShared::add_unregistered_class(InstanceKlass* k, TRAPS) {
   assert(DumpSharedSpaces, "only when dumping");
-  assert(boot_loader_dictionary() != NULL, "must be");
 
-  if (boot_loader_dictionary()->add_non_builtin_klass(name, loader_data, k)) {
-    MutexLocker mu_r(Compile_lock, THREAD); // not really necessary, but add_to_hierarchy asserts this.
-    add_to_hierarchy(k, CHECK_0);
+  Symbol* name = k->name();
+  if (_loaded_unregistered_classes.get(name) != NULL) {
+    // We don't allow duplicated unregistered classes of the same name.
+    return false;
+  } else {
+    bool isnew = _loaded_unregistered_classes.put(name, true);
+    assert(isnew, "sanity");
+    MutexLocker mu_r(Compile_lock, THREAD); // add_to_hierarchy asserts this.
+    SystemDictionary::add_to_hierarchy(k, CHECK_0);
     return true;
   }
-  return false;
 }
 
 // This function is called to resolve the super/interfaces of shared classes for
@@ -698,81 +959,138 @@
   }
 }
 
-struct SharedMiscInfo {
-  InstanceKlass* _klass;
-  int _clsfile_size;
-  int _clsfile_crc32;
-};
-
-static GrowableArray<SharedMiscInfo>* misc_info_array = NULL;
+DumpTimeSharedClassInfo* SystemDictionaryShared::find_or_allocate_info_for(InstanceKlass* k) {
+  if (_dumptime_table == NULL) {
+    _dumptime_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeSharedClassTable();
+  }
+  return _dumptime_table->find_or_allocate_info_for(k);
+}
 
 void SystemDictionaryShared::set_shared_class_misc_info(InstanceKlass* k, ClassFileStream* cfs) {
   assert(DumpSharedSpaces, "only when dumping");
-  int clsfile_size  = cfs->length();
-  int clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length());
-
-  if (misc_info_array == NULL) {
-    misc_info_array = new (ResourceObj::C_HEAP, mtClass) GrowableArray<SharedMiscInfo>(20, /*c heap*/ true);
-  }
-
-  SharedMiscInfo misc_info;
-  DEBUG_ONLY({
-      for (int i=0; i<misc_info_array->length(); i++) {
-        misc_info = misc_info_array->at(i);
-        assert(misc_info._klass != k, "cannot call set_shared_class_misc_info twice for the same class");
-      }
-    });
-
-  misc_info._klass = k;
-  misc_info._clsfile_size = clsfile_size;
-  misc_info._clsfile_crc32 = clsfile_crc32;
-
-  misc_info_array->append(misc_info);
+  assert(!is_builtin(k), "must be unregistered class");
+  DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
+  info->_clsfile_size  = cfs->length();
+  info->_clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length());
 }
 
-void SystemDictionaryShared::init_shared_dictionary_entry(InstanceKlass* k, DictionaryEntry* ent) {
-  SharedDictionaryEntry* entry = (SharedDictionaryEntry*)ent;
-  entry->_id = -1;
-  entry->_clsfile_size = -1;
-  entry->_clsfile_crc32 = -1;
-  entry->_verifier_constraints = NULL;
-  entry->_verifier_constraint_flags = NULL;
+void SystemDictionaryShared::init_dumptime_info(InstanceKlass* k) {
+  (void)find_or_allocate_info_for(k);
+}
 
-  if (misc_info_array != NULL) {
-    for (int i=0; i<misc_info_array->length(); i++) {
-      SharedMiscInfo misc_info = misc_info_array->at(i);
-      if (misc_info._klass == k) {
-        entry->_clsfile_size = misc_info._clsfile_size;
-        entry->_clsfile_crc32 = misc_info._clsfile_crc32;
-        misc_info_array->remove_at(i);
-        return;
-      }
+void SystemDictionaryShared::remove_dumptime_info(InstanceKlass* k) {
+  _dumptime_table->remove(k);
+}
+
+bool SystemDictionaryShared::is_jfr_event_class(InstanceKlass *k) {
+  while (k) {
+    if (k->name()->equals("jdk/internal/event/Event")) {
+      return true;
     }
+    k = k->java_super();
   }
+  return false;
+}
+
+void SystemDictionaryShared::warn_excluded(InstanceKlass* k, const char* reason) {
+  ResourceMark rm;
+  log_warning(cds)("Skipping %s: %s", k->name()->as_C_string(), reason);
+}
+
+bool SystemDictionaryShared::should_be_excluded(InstanceKlass* k) {
+  if (k->class_loader_data()->is_unsafe_anonymous()) {
+    return true; // unsafe anonymous classes are not archived, skip
+  }
+  if (k->is_in_error_state()) {
+    return true;
+  }
+  if (k->shared_classpath_index() < 0 && is_builtin(k)) {
+    // These are classes loaded from unsupported locations (such as those loaded by JVMTI native
+    // agent during dump time).
+    warn_excluded(k, "Unsupported location");
+    return true;
+  }
+  if (k->signers() != NULL) {
+    // We cannot include signed classes in the archive because the certificates
+    // used during dump time may be different than those used during
+    // runtime (due to expiration, etc).
+    warn_excluded(k, "Signed JAR");
+    return true;
+  }
+  if (is_jfr_event_class(k)) {
+    // We cannot include JFR event classes because they need runtime-specific
+    // instrumentation in order to work with -XX:FlightRecorderOptions=retransform=false.
+    // There are only a small number of these classes, so it's not worthwhile to
+    // support them and make CDS more complicated.
+    warn_excluded(k, "JFR event class");
+    return true;
+  }
+  return false;
+}
+
+// k is a class before relocating by ArchiveCompactor
+void SystemDictionaryShared::validate_before_archiving(InstanceKlass* k) {
+  ResourceMark rm;
+  const char* name = k->name()->as_C_string();
+  DumpTimeSharedClassInfo* info = _dumptime_table->get(k);
+  guarantee(info != NULL, "Class %s must be entered into _dumptime_table", name);
+  guarantee(!info->_excluded, "Should not attempt to archive excluded class %s", name);
+  if (is_builtin(k)) {
+    guarantee(k->loader_type() != 0,
+              "Class loader type must be set for BUILTIN class %s", name);
+  } else {
+    guarantee(k->loader_type() == 0,
+              "Class loader type must not be set for UNREGISTERED class %s", name);
+  }
+}
+
+class ExcludeDumpTimeSharedClasses : StackObj {
+public:
+  bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
+    if (SystemDictionaryShared::should_be_excluded(k)) {
+      info._excluded = true;
+    }
+    return true; // keep on iterating
+  }
+};
+
+void SystemDictionaryShared::check_excluded_classes() {
+  ExcludeDumpTimeSharedClasses excl;
+  _dumptime_table->iterate(&excl);
+  DEBUG_ONLY(_checked_excluded_classes = true;)
+}
+
+bool SystemDictionaryShared::is_excluded_class(InstanceKlass* k) {
+  assert(_checked_excluded_classes, "sanity");
+  assert(DumpSharedSpaces, "only when dumping");
+  return find_or_allocate_info_for(k)->_excluded;
+}
+
+class IterateDumpTimeSharedClassTable : StackObj {
+  MetaspaceClosure *_it;
+public:
+  IterateDumpTimeSharedClassTable(MetaspaceClosure* it) : _it(it) {}
+
+  bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
+    if (!info._excluded) {
+      info.metaspace_pointers_do(_it);
+    }
+    return true; // keep on iterating
+  }
+};
+
+void SystemDictionaryShared::dumptime_classes_do(class MetaspaceClosure* it) {
+  IterateDumpTimeSharedClassTable iter(it);
+  _dumptime_table->iterate(&iter);
 }
 
 bool SystemDictionaryShared::add_verification_constraint(InstanceKlass* k, Symbol* name,
          Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object) {
   assert(DumpSharedSpaces, "called at dump time only");
-
-  // Skip unsafe anonymous classes, which are not archived as they are not in
-  // dictionary (see assert_no_unsafe_anonymous_classes_in_dictionaries() in
-  // VM_PopulateDumpSharedSpace::doit()).
-  if (k->class_loader_data()->is_unsafe_anonymous()) {
-    return true; // unsafe anonymous classes are not archived, skip
-  }
-
-  SharedDictionaryEntry* entry = ((SharedDictionary*)(k->class_loader_data()->dictionary()))->find_entry_for(k);
-  ResourceMark rm;
-  // Lambda classes are not archived and will be regenerated at runtime.
-  if (entry == NULL) {
-    guarantee(strstr(k->name()->as_C_string(), "Lambda$") != NULL,
-              "class should be in dictionary before being verified");
-    return true;
-  }
-  entry->add_verification_constraint(name, from_name, from_field_is_protected,
-                                     from_is_array, from_is_object);
-  if (entry->is_builtin()) {
+  DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
+  info->add_verification_constraint(k, name, from_name, from_field_is_protected,
+                                    from_is_array, from_is_object);
+  if (is_builtin(k)) {
     // For builtin class loaders, we can try to complete the verification check at dump time,
     // because we can resolve all the constraint classes.
     return false;
@@ -783,135 +1101,54 @@
   }
 }
 
-void SystemDictionaryShared::finalize_verification_constraints_for(InstanceKlass* k) {
-  if (!k->is_unsafe_anonymous()) {
-    SharedDictionaryEntry* entry = ((SharedDictionary*)(k->class_loader_data()->dictionary()))->find_entry_for(k);
-    entry->finalize_verification_constraints();
-  }
-}
-
-void SystemDictionaryShared::finalize_verification_constraints() {
-  MutexLocker mcld(ClassLoaderDataGraph_lock);
-  ClassLoaderDataGraph::dictionary_classes_do(finalize_verification_constraints_for);
-}
-
-void SystemDictionaryShared::check_verification_constraints(InstanceKlass* klass,
-                                                             TRAPS) {
-  assert(!DumpSharedSpaces && UseSharedSpaces, "called at run time with CDS enabled only");
-  SharedDictionaryEntry* entry = shared_dictionary()->find_entry_for(klass);
-  assert(entry != NULL, "call this only for shared classes");
-  entry->check_verification_constraints(klass, THREAD);
-}
-
-SharedDictionaryEntry* SharedDictionary::find_entry_for(InstanceKlass* klass) {
-  Symbol* class_name = klass->name();
-  unsigned int hash = compute_hash(class_name);
-  int index = hash_to_index(hash);
-
-  for (SharedDictionaryEntry* entry = bucket(index);
-                              entry != NULL;
-                              entry = entry->next()) {
-    if (entry->hash() == hash && entry->literal() == klass) {
-      return entry;
-    }
-  }
-
-  return NULL;
-}
-
-void SharedDictionaryEntry::add_verification_constraint(Symbol* name,
+void DumpTimeSharedClassInfo::add_verification_constraint(InstanceKlass* k, Symbol* name,
          Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object) {
   if (_verifier_constraints == NULL) {
-    _verifier_constraints = new(ResourceObj::C_HEAP, mtClass) GrowableArray<Symbol*>(8, true, mtClass);
+    _verifier_constraints = new(ResourceObj::C_HEAP, mtClass) GrowableArray<DTConstraint>(4, true, mtClass);
   }
   if (_verifier_constraint_flags == NULL) {
     _verifier_constraint_flags = new(ResourceObj::C_HEAP, mtClass) GrowableArray<char>(4, true, mtClass);
   }
-  GrowableArray<Symbol*>* vc_array = (GrowableArray<Symbol*>*)_verifier_constraints;
-  for (int i=0; i<vc_array->length(); i+= 2) {
-    if (name      == vc_array->at(i) &&
-        from_name == vc_array->at(i+1)) {
+  GrowableArray<DTConstraint>* vc_array = _verifier_constraints;
+  for (int i = 0; i < vc_array->length(); i++) {
+    DTConstraint* p = vc_array->adr_at(i);
+    if (name == p->_name && from_name == p->_from_name) {
       return;
     }
   }
-  vc_array->append(name);
-  vc_array->append(from_name);
+  DTConstraint cons(name, from_name);
+  vc_array->append(cons);
 
-  GrowableArray<char>* vcflags_array = (GrowableArray<char>*)_verifier_constraint_flags;
+  GrowableArray<char>* vcflags_array = _verifier_constraint_flags;
   char c = 0;
-  c |= from_field_is_protected ? FROM_FIELD_IS_PROTECTED : 0;
-  c |= from_is_array           ? FROM_IS_ARRAY           : 0;
-  c |= from_is_object          ? FROM_IS_OBJECT          : 0;
+  c |= from_field_is_protected ? SystemDictionaryShared::FROM_FIELD_IS_PROTECTED : 0;
+  c |= from_is_array           ? SystemDictionaryShared::FROM_IS_ARRAY           : 0;
+  c |= from_is_object          ? SystemDictionaryShared::FROM_IS_OBJECT          : 0;
   vcflags_array->append(c);
 
   if (log_is_enabled(Trace, cds, verification)) {
     ResourceMark rm;
     log_trace(cds, verification)("add_verification_constraint: %s: %s must be subclass of %s",
-                                 instance_klass()->external_name(), from_name->as_klass_external_name(),
+                                 k->external_name(), from_name->as_klass_external_name(),
                                  name->as_klass_external_name());
   }
 }
 
-int SharedDictionaryEntry::finalize_verification_constraints() {
-  assert(DumpSharedSpaces, "called at dump time only");
-  Thread* THREAD = Thread::current();
-  ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
-  GrowableArray<Symbol*>* vc_array = (GrowableArray<Symbol*>*)_verifier_constraints;
-  GrowableArray<char>* vcflags_array = (GrowableArray<char>*)_verifier_constraint_flags;
+void SystemDictionaryShared::check_verification_constraints(InstanceKlass* klass,
+                                                            TRAPS) {
+  assert(!DumpSharedSpaces && UseSharedSpaces, "called at run time with CDS enabled only");
+  RunTimeSharedClassInfo* record = RunTimeSharedClassInfo::get_for(klass);
 
-  if (vc_array != NULL) {
-    if (log_is_enabled(Trace, cds, verification)) {
-      ResourceMark rm;
-      log_trace(cds, verification)("finalize_verification_constraint: %s",
-                                   literal()->external_name());
-    }
+  int length = record->_num_constraints;
+  if (length > 0) {
+    for (int i = 0; i < length; i++) {
+      Symbol* name      = record->get_constraint_name(i);
+      Symbol* from_name = record->get_constraint_from_name(i);
+      char c            = record->get_constraint_flag(i);
 
-    // Copy the constraints from C_HEAP-alloced GrowableArrays to Metaspace-alloced
-    // Arrays
-    int size = 0;
-    {
-      // FIXME: change this to be done after relocation, so we can use symbol offset??
-      int length = vc_array->length();
-      Array<Symbol*>* out = MetadataFactory::new_array<Symbol*>(loader_data, length, 0, THREAD);
-      assert(out != NULL, "Dump time allocation failure would have aborted VM");
-      for (int i=0; i<length; i++) {
-        out->at_put(i, vc_array->at(i));
-      }
-      _verifier_constraints = out;
-      size += out->size() * BytesPerWord;
-      delete vc_array;
-    }
-    {
-      int length = vcflags_array->length();
-      Array<char>* out = MetadataFactory::new_array<char>(loader_data, length, 0, THREAD);
-      assert(out != NULL, "Dump time allocation failure would have aborted VM");
-      for (int i=0; i<length; i++) {
-        out->at_put(i, vcflags_array->at(i));
-      }
-      _verifier_constraint_flags = out;
-      size += out->size() * BytesPerWord;
-      delete vcflags_array;
-    }
-
-    return size;
-  }
-  return 0;
-}
-
-void SharedDictionaryEntry::check_verification_constraints(InstanceKlass* klass, TRAPS) {
-  Array<Symbol*>* vc_array = (Array<Symbol*>*)_verifier_constraints;
-  Array<char>* vcflags_array = (Array<char>*)_verifier_constraint_flags;
-
-  if (vc_array != NULL) {
-    int length = vc_array->length();
-    for (int i=0; i<length; i+=2) {
-      Symbol* name      = vc_array->at(i);
-      Symbol* from_name = vc_array->at(i+1);
-      char c = vcflags_array->at(i/2);
-
-      bool from_field_is_protected = (c & FROM_FIELD_IS_PROTECTED) ? true : false;
-      bool from_is_array           = (c & FROM_IS_ARRAY)           ? true : false;
-      bool from_is_object          = (c & FROM_IS_OBJECT)          ? true : false;
+      bool from_field_is_protected = (c & SystemDictionaryShared::FROM_FIELD_IS_PROTECTED) ? true : false;
+      bool from_is_array           = (c & SystemDictionaryShared::FROM_IS_ARRAY)           ? true : false;
+      bool from_is_object          = (c & SystemDictionaryShared::FROM_IS_OBJECT)          ? true : false;
 
       bool ok = VerificationType::resolve_and_check_assignability(klass, name,
          from_name, from_field_is_protected, from_is_array, from_is_object, CHECK);
@@ -930,132 +1167,100 @@
   }
 }
 
-void SharedDictionaryEntry::metaspace_pointers_do(MetaspaceClosure* it) {
-  it->push((Array<Symbol*>**)&_verifier_constraints);
-  it->push((Array<char>**)&_verifier_constraint_flags);
+class CopySharedClassInfoToArchive : StackObj {
+  CompactHashtableWriter* _writer;
+  bool _is_builtin;
+public:
+  CopySharedClassInfoToArchive(CompactHashtableWriter* writer, bool is_builtin)
+    : _writer(writer), _is_builtin(is_builtin) {}
+
+  bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
+    if (!info._excluded && info.is_builtin() == _is_builtin) {
+      size_t byte_size = RunTimeSharedClassInfo::byte_size(info._klass, info.num_constraints());
+      RunTimeSharedClassInfo* record =
+        (RunTimeSharedClassInfo*)MetaspaceShared::read_only_space_alloc(byte_size);
+      record->init(info);
+
+      unsigned int hash = primitive_hash<Symbol*>(info._klass->name());
+      _writer->add(hash, MetaspaceShared::object_delta_u4(record));
+
+      // Save this for quick runtime lookup of InstanceKlass* -> RunTimeSharedClassInfo*
+      RunTimeSharedClassInfo::set_for(info._klass, record);
+    }
+    return true; // keep on iterating
+  }
+};
+
+void SystemDictionaryShared::write_dictionary(RunTimeSharedDictionary* dictionary, bool is_builtin) {
+  CompactHashtableStats stats;
+  dictionary->reset();
+  int num_buckets = CompactHashtableWriter::default_num_buckets(_dumptime_table->count_of(is_builtin));
+  CompactHashtableWriter writer(num_buckets, &stats);
+  CopySharedClassInfoToArchive copy(&writer, is_builtin);
+  _dumptime_table->iterate(&copy);
+  writer.dump(dictionary, is_builtin ? "builtin dictionary" : "unregistered dictionary");
 }
 
-bool SharedDictionary::add_non_builtin_klass(const Symbol* class_name,
-                                             ClassLoaderData* loader_data,
-                                             InstanceKlass* klass) {
-
-  assert(DumpSharedSpaces, "supported only when dumping");
-  assert(klass != NULL, "adding NULL klass");
-  assert(klass->name() == class_name, "sanity check on name");
-  assert(klass->shared_classpath_index() < 0,
-         "the shared classpath index should not be set for shared class loaded by the custom loaders");
-
-  // Add an entry for a non-builtin class.
-  // For a shared class for custom class loaders, SystemDictionary::resolve_or_null will
-  // not find this class, because is_builtin() is false.
-  unsigned int hash = compute_hash(class_name);
-  int index = hash_to_index(hash);
-
-  for (SharedDictionaryEntry* entry = bucket(index);
-                              entry != NULL;
-                              entry = entry->next()) {
-    if (entry->hash() == hash) {
-      InstanceKlass* klass = entry->instance_klass();
-      if (klass->name() == class_name && klass->class_loader_data() == loader_data) {
-        // There is already a class defined with the same name
-        return false;
-      }
-    }
-  }
-
-  assert(Dictionary::entry_size() >= sizeof(SharedDictionaryEntry), "must be big enough");
-  SharedDictionaryEntry* entry = (SharedDictionaryEntry*)new_entry(hash, klass);
-  add_entry(index, entry);
-
-  assert(entry->is_unregistered(), "sanity");
-  assert(!entry->is_builtin(), "sanity");
-  return true;
+void SystemDictionaryShared::write_to_archive() {
+  _dumptime_table->update_counts();
+  write_dictionary(&_builtin_dictionary, true);
+  write_dictionary(&_unregistered_dictionary, false);
 }
 
-
-//-----------------
-// SharedDictionary
-//-----------------
-
-
-InstanceKlass* SharedDictionary::find_class_for_builtin_loader(const Symbol* name) const {
-  SharedDictionaryEntry* entry = get_entry_for_builtin_loader(name);
-  return entry != NULL ? entry->instance_klass() : (InstanceKlass*)NULL;
+void SystemDictionaryShared::serialize_dictionary_headers(SerializeClosure* soc) {
+  _builtin_dictionary.serialize_header(soc);
+  _unregistered_dictionary.serialize_header(soc);
 }
 
-InstanceKlass* SharedDictionary::find_class_for_unregistered_loader(const Symbol* name,
-                                                            int clsfile_size,
-                                                            int clsfile_crc32) const {
-
-  const SharedDictionaryEntry* entry = get_entry_for_unregistered_loader(name,
-                                                                         clsfile_size,
-                                                                         clsfile_crc32);
-  return entry != NULL ? entry->instance_klass() : NULL;
+const RunTimeSharedClassInfo*
+SystemDictionaryShared::find_record(RunTimeSharedDictionary* dict, Symbol* name) {
+  if (UseSharedSpaces) {
+    unsigned int hash = primitive_hash<Symbol*>(name);
+    return dict->lookup(name, hash, 0);
+  } else {
+    return NULL;
+  }
 }
 
-void SharedDictionary::update_entry(InstanceKlass* klass, int id) {
-  assert(DumpSharedSpaces, "supported only when dumping");
-  Symbol* class_name = klass->name();
-  unsigned int hash = compute_hash(class_name);
-  int index = hash_to_index(hash);
-
-  for (SharedDictionaryEntry* entry = bucket(index);
-                              entry != NULL;
-                              entry = entry->next()) {
-    if (entry->hash() == hash && entry->literal() == klass) {
-      entry->_id = id;
-      return;
-    }
+InstanceKlass* SystemDictionaryShared::find_builtin_class(Symbol* name) {
+  const RunTimeSharedClassInfo* record = find_record(&_builtin_dictionary, name);
+  if (record) {
+    return record->_klass;
+  } else {
+    return NULL;
   }
-
-  ShouldNotReachHere();
 }
 
-SharedDictionaryEntry* SharedDictionary::get_entry_for_builtin_loader(const Symbol* class_name) const {
-  assert(!DumpSharedSpaces, "supported only when at runtime");
-  unsigned int hash = compute_hash(class_name);
-  const int index = hash_to_index(hash);
-
-  for (SharedDictionaryEntry* entry = bucket(index);
-                              entry != NULL;
-                              entry = entry->next()) {
-    if (entry->hash() == hash && entry->equals(class_name)) {
-      if (entry->is_builtin()) {
-        return entry;
-      }
-    }
-  }
-  return NULL;
+void SystemDictionaryShared::update_shared_entry(InstanceKlass* k, int id) {
+  assert(DumpSharedSpaces, "supported only when dumping");
+  DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
+  info->_id = id;
 }
 
-SharedDictionaryEntry* SharedDictionary::get_entry_for_unregistered_loader(const Symbol* class_name,
-                                                                           int clsfile_size,
-                                                                           int clsfile_crc32) const {
-  assert(!DumpSharedSpaces, "supported only when at runtime");
-  unsigned int hash = compute_hash(class_name);
-  int index = hash_to_index(hash);
+class SharedDictionaryPrinter : StackObj {
+  outputStream* _st;
+  int _index;
+public:
+  SharedDictionaryPrinter(outputStream* st) : _st(st), _index(0) {}
 
-  for (SharedDictionaryEntry* entry = bucket(index);
-                              entry != NULL;
-                              entry = entry->next()) {
-    if (entry->hash() == hash && entry->equals(class_name)) {
-      if (entry->is_unregistered()) {
-        if (clsfile_size == -1) {
-          // We're called from class_exists_for_unregistered_loader. At run time, we want to
-          // compute the CRC of a ClassFileStream only if there is an UNREGISTERED class
-          // with the matching name.
-          return entry;
-        } else {
-          // We're called from find_class_for_unregistered_loader
-          if (entry->_clsfile_size && clsfile_crc32 == entry->_clsfile_crc32) {
-            return entry;
-          }
-        }
+  void do_value(const RunTimeSharedClassInfo* record) {
+    ResourceMark rm;
+    _st->print_cr("%4d:  %s", (_index++), record->_klass->external_name());
+  }
+};
 
-        // There can be only 1 class with this name for unregistered loaders.
-        return NULL;
-      }
-    }
+void SystemDictionaryShared::print_on(outputStream* st) {
+  if (UseSharedSpaces) {
+    st->print_cr("Shared Dictionary");
+    SharedDictionaryPrinter p(st);
+    _builtin_dictionary.iterate(&p);
+    _unregistered_dictionary.iterate(&p);
   }
-  return NULL;
 }
+
+void SystemDictionaryShared::print_table_statistics(outputStream* st) {
+  if (UseSharedSpaces) {
+    _builtin_dictionary.print_table_statistics(st, "Builtin Shared Dictionary");
+    _unregistered_dictionary.print_table_statistics(st, "Unregistered Shared Dictionary");
+  }
+}
--- a/src/hotspot/share/classfile/systemDictionaryShared.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -36,13 +36,12 @@
     Handling of the classes in the AppCDS archive
 
     To ensure safety and to simplify the implementation, archived classes are
-    "segregated" into several types. The following rules describe how they
+    "segregated" into 2 types. The following rules describe how they
     are stored and looked up.
 
 [1] Category of archived classes
 
-    There are 3 disjoint groups of classes stored in the AppCDS archive. They are
-    categorized as by their SharedDictionaryEntry::loader_type()
+    There are 2 disjoint groups of classes stored in the AppCDS archive:
 
     BUILTIN:              These classes may be defined ONLY by the BOOT/PLATFORM/APP
                           loaders.
@@ -83,112 +82,39 @@
     Bar id: 3 super: 0 interfaces: 1 source: /foo.jar
 
 
-[3] Identifying the loader_type of archived classes in the shared dictionary
-
-    Each archived Klass* C is associated with a SharedDictionaryEntry* E
+[3] Identifying the category of archived classes
 
     BUILTIN:              (C->shared_classpath_index() >= 0)
-    UNREGISTERED:         (C->shared_classpath_index() <  0)
+    UNREGISTERED:         (C->shared_classpath_index() == UNREGISTERED_INDEX (-9999))
 
 [4] Lookup of archived classes at run time:
 
     (a) BUILTIN loaders:
 
-        Search the shared directory for a BUILTIN class with a matching name.
+        search _builtin_dictionary
 
     (b) UNREGISTERED loaders:
 
-        The search originates with SystemDictionaryShared::lookup_from_stream().
-
-        Search the shared directory for a UNREGISTERED class with a matching
-        (name, clsfile_len, clsfile_crc32) tuple.
+        search _unregistered_dictionary for an entry that matches the
+        (name, clsfile_len, clsfile_crc32).
 
 ===============================================================================*/
 #define UNREGISTERED_INDEX -9999
 
 class ClassFileStream;
+class DumpTimeSharedClassInfo;
+class DumpTimeSharedClassTable;
+class RunTimeSharedClassInfo;
+class RunTimeSharedDictionary;
 
-// Archived classes need extra information not needed by traditionally loaded classes.
-// To keep footprint small, we add these in the dictionary entry instead of the InstanceKlass.
-class SharedDictionaryEntry : public DictionaryEntry {
-
+class SystemDictionaryShared: public SystemDictionary {
 public:
-  enum LoaderType {
-    LT_BUILTIN,
-    LT_UNREGISTERED
-  };
-
   enum {
     FROM_FIELD_IS_PROTECTED = 1 << 0,
     FROM_IS_ARRAY           = 1 << 1,
     FROM_IS_OBJECT          = 1 << 2
   };
 
-  int             _id;
-  int             _clsfile_size;
-  int             _clsfile_crc32;
-  void*           _verifier_constraints; // FIXME - use a union here to avoid type casting??
-  void*           _verifier_constraint_flags;
-
-  // See "Identifying the loader_type of archived classes" comments above.
-  LoaderType loader_type() const {
-    InstanceKlass* k = instance_klass();
-
-    if ((k->shared_classpath_index() != UNREGISTERED_INDEX)) {
-      return LT_BUILTIN;
-    } else {
-      return LT_UNREGISTERED;
-    }
-  }
-
-  SharedDictionaryEntry* next() {
-    return (SharedDictionaryEntry*)(DictionaryEntry::next());
-  }
-
-  bool is_builtin() const {
-    return loader_type() == LT_BUILTIN;
-  }
-  bool is_unregistered() const {
-    return loader_type() == LT_UNREGISTERED;
-  }
-
-  void add_verification_constraint(Symbol* name,
-         Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object);
-  int finalize_verification_constraints();
-  void check_verification_constraints(InstanceKlass* klass, TRAPS);
-  void metaspace_pointers_do(MetaspaceClosure* it) NOT_CDS_RETURN;
-};
-
-class SharedDictionary : public Dictionary {
-  SharedDictionaryEntry* get_entry_for_builtin_loader(const Symbol* name) const;
-  SharedDictionaryEntry* get_entry_for_unregistered_loader(const Symbol* name,
-                                                           int clsfile_size,
-                                                           int clsfile_crc32) const;
-
-  // Convenience functions
-  SharedDictionaryEntry* bucket(int index) const {
-    return (SharedDictionaryEntry*)(Dictionary::bucket(index));
-  }
-
-public:
-  SharedDictionaryEntry* find_entry_for(InstanceKlass* klass);
-
-  bool add_non_builtin_klass(const Symbol* class_name,
-                             ClassLoaderData* loader_data,
-                             InstanceKlass* obj);
-
-  void update_entry(InstanceKlass* klass, int id);
-
-  InstanceKlass* find_class_for_builtin_loader(const Symbol* name) const;
-  InstanceKlass* find_class_for_unregistered_loader(const Symbol* name,
-                                            int clsfile_size,
-                                            int clsfile_crc32) const;
-  bool class_exists_for_unregistered_loader(const Symbol* name) {
-    return (get_entry_for_unregistered_loader(name, -1, -1) != NULL);
-  }
-};
-
-class SystemDictionaryShared: public SystemDictionary {
 private:
   // These _shared_xxxs arrays are used to initialize the java.lang.Package and
   // java.security.ProtectionDomain objects associated with each shared class.
@@ -282,8 +208,17 @@
                                  Handle class_loader,
                                  Handle protection_domain,
                                  TRAPS);
-  static void finalize_verification_constraints_for(InstanceKlass* k);
+  static DumpTimeSharedClassInfo* find_or_allocate_info_for(InstanceKlass* k);
+  static void write_dictionary(RunTimeSharedDictionary* dictionary, bool is_builtin);
+  static bool is_jfr_event_class(InstanceKlass *k);
+  static void warn_excluded(InstanceKlass* k, const char* reason);
+
+  DEBUG_ONLY(static bool _checked_excluded_classes;)
 public:
+  static InstanceKlass* find_builtin_class(Symbol* class_name);
+
+  static const RunTimeSharedClassInfo* find_record(RunTimeSharedDictionary* dict, Symbol* name);
+
   // Called by PLATFORM/APP loader only
   static InstanceKlass* find_or_load_shared_class(Symbol* class_name,
                                                Handle class_loader,
@@ -311,8 +246,7 @@
     return NULL;
   }
 
-  static bool add_non_builtin_klass(Symbol* class_name, ClassLoaderData* loader_data,
-                                    InstanceKlass* k, TRAPS);
+  static bool add_unregistered_class(InstanceKlass* k, TRAPS);
   static InstanceKlass* dump_time_resolve_super_or_fail(Symbol* child_name,
                                                 Symbol* class_name,
                                                 Handle class_loader,
@@ -320,36 +254,17 @@
                                                 bool is_superclass,
                                                 TRAPS);
 
-  static size_t dictionary_entry_size() {
-    return (DumpSharedSpaces) ? sizeof(SharedDictionaryEntry) : sizeof(DictionaryEntry);
-  }
-  static void init_shared_dictionary_entry(InstanceKlass* k, DictionaryEntry* entry) NOT_CDS_RETURN;
-  static bool is_builtin(DictionaryEntry* ent) {
-    // Can't use virtual function is_builtin because DictionaryEntry doesn't initialize
-    // vtable because it's not constructed properly.
-    SharedDictionaryEntry* entry = (SharedDictionaryEntry*)ent;
-    return entry->is_builtin();
+  static void init_dumptime_info(InstanceKlass* k) NOT_CDS_RETURN;
+  static void remove_dumptime_info(InstanceKlass* k) NOT_CDS_RETURN;
+
+  static Dictionary* boot_loader_dictionary() {
+    return ClassLoaderData::the_null_class_loader_data()->dictionary();
   }
 
-  // For convenient access to the SharedDictionaryEntry's of the archived classes.
-  static SharedDictionary* shared_dictionary() {
-    assert(!DumpSharedSpaces, "not for dumping");
-    return (SharedDictionary*)SystemDictionary::shared_dictionary();
-  }
-
-  static SharedDictionary* boot_loader_dictionary() {
-    return (SharedDictionary*)ClassLoaderData::the_null_class_loader_data()->dictionary();
-  }
-
-  static void update_shared_entry(InstanceKlass* klass, int id) {
-    assert(DumpSharedSpaces, "sanity");
-    assert((SharedDictionary*)(klass->class_loader_data()->dictionary()) != NULL, "sanity");
-    ((SharedDictionary*)(klass->class_loader_data()->dictionary()))->update_entry(klass, id);
-  }
-
+  static void update_shared_entry(InstanceKlass* klass, int id);
   static void set_shared_class_misc_info(InstanceKlass* k, ClassFileStream* cfs);
 
-  static InstanceKlass* lookup_from_stream(const Symbol* class_name,
+  static InstanceKlass* lookup_from_stream(Symbol* class_name,
                                            Handle class_loader,
                                            Handle protection_domain,
                                            const ClassFileStream* st,
@@ -366,9 +281,23 @@
   static bool add_verification_constraint(InstanceKlass* k, Symbol* name,
                   Symbol* from_name, bool from_field_is_protected,
                   bool from_is_array, bool from_is_object) NOT_CDS_RETURN_(false);
-  static void finalize_verification_constraints() NOT_CDS_RETURN;
   static void check_verification_constraints(InstanceKlass* klass,
-                                              TRAPS) NOT_CDS_RETURN;
+                                             TRAPS) NOT_CDS_RETURN;
+  static bool is_builtin(InstanceKlass* k) {
+    return (k->shared_classpath_index() != UNREGISTERED_INDEX);
+  }
+  static bool should_be_excluded(InstanceKlass* k);
+  static void check_excluded_classes();
+  static void validate_before_archiving(InstanceKlass* k);
+  static bool is_excluded_class(InstanceKlass* k);
+  static void dumptime_classes_do(class MetaspaceClosure* it);
+  static void write_to_archive();
+  static void serialize_dictionary_headers(class SerializeClosure* soc);
+  static void print() { return print_on(tty); }
+  static void print_on(outputStream* st) NOT_CDS_RETURN;
+  static void print_table_statistics(outputStream* st) NOT_CDS_RETURN;
+
+  DEBUG_ONLY(static bool checked_excluded_classes() {return _checked_excluded_classes;})
 };
 
 #endif // SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP
--- a/src/hotspot/share/code/codeBlob.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/code/codeBlob.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -393,6 +393,10 @@
   BufferBlob(const char* name, int size);
   BufferBlob(const char* name, int size, CodeBuffer* cb);
 
+  // This ordinary operator delete is needed even though not used, so the
+  // below two-argument operator delete will be treated as a placement
+  // delete rather than an ordinary sized delete; see C++14 3.7.4.2/p2.
+  void operator delete(void* p);
   void* operator new(size_t s, unsigned size) throw();
 
  public:
@@ -476,6 +480,10 @@
     bool        caller_must_gc_arguments
   );
 
+  // This ordinary operator delete is needed even though not used, so the
+  // below two-argument operator delete will be treated as a placement
+  // delete rather than an ordinary sized delete; see C++14 3.7.4.2/p2.
+  void operator delete(void* p);
   void* operator new(size_t s, unsigned size) throw();
 
  public:
@@ -511,6 +519,10 @@
   friend class VMStructs;
 
  protected:
+  // This ordinary operator delete is needed even though not used, so the
+  // below two-argument operator delete will be treated as a placement
+  // delete rather than an ordinary sized delete; see C++14 3.7.4.2/p2.
+  void operator delete(void* p);
   void* operator new(size_t s, unsigned size) throw();
 
  public:
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -1655,7 +1655,7 @@
   // Unload Klasses, String, Code Cache, etc.
   if (ClassUnloadingWithConcurrentMark) {
     GCTraceTime(Debug, gc, phases) debug("Class Unloading", _gc_timer_cm);
-    bool purged_classes = SystemDictionary::do_unloading(_gc_timer_cm, false /* Defer cleaning */);
+    bool purged_classes = SystemDictionary::do_unloading(_gc_timer_cm);
     _g1h->complete_cleaning(&g1_is_alive, purged_classes);
   } else {
     GCTraceTime(Debug, gc, phases) debug("Cleanup", _gc_timer_cm);
--- a/src/hotspot/share/memory/allocation.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/memory/allocation.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -244,6 +244,7 @@
 class MetaspaceClosure;
 
 class MetaspaceObj {
+  friend class VMStructs;
   // When CDS is enabled, all shared metaspace objects are mapped
   // into a single contiguous memory block, so we can use these
   // two pointers to quickly determine if something is in the
--- a/src/hotspot/share/memory/filemap.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/memory/filemap.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -209,6 +209,7 @@
   _verify_local = BytecodeVerificationLocal;
   _verify_remote = BytecodeVerificationRemote;
   _has_platform_or_app_classes = ClassLoaderExt::has_platform_or_app_classes();
+  _shared_base_address = SharedBaseAddress;
 }
 
 void SharedClassPathEntry::init(const char* name, bool is_modules_image, TRAPS) {
@@ -533,6 +534,7 @@
   }
 
   _file_offset += (long)n;
+  SharedBaseAddress = _header->_shared_base_address;
   return true;
 }
 
@@ -666,7 +668,8 @@
 //             +-- gap
 size_t FileMapInfo::write_archive_heap_regions(GrowableArray<MemRegion> *heap_mem,
                                                GrowableArray<ArchiveHeapOopmapInfo> *oopmaps,
-                                               int first_region_id, int max_num_regions) {
+                                               int first_region_id, int max_num_regions,
+                                               bool print_log) {
   assert(max_num_regions <= 2, "Only support maximum 2 memory regions");
 
   int arr_len = heap_mem == NULL ? 0 : heap_mem->length();
@@ -687,8 +690,10 @@
       total_size += size;
     }
 
-    log_info(cds)("Archive heap region %d " INTPTR_FORMAT " - " INTPTR_FORMAT " = " SIZE_FORMAT_W(8) " bytes",
-                  i, p2i(start), p2i(start + size), size);
+    if (print_log) {
+      log_info(cds)("Archive heap region %d " INTPTR_FORMAT " - " INTPTR_FORMAT " = " SIZE_FORMAT_W(8) " bytes",
+                    i, p2i(start), p2i(start + size), size);
+    }
     write_region(i, start, size, false, false);
     if (size > 0) {
       space_at(i)->_oopmap = oopmaps->at(arr_idx)._oopmap;
--- a/src/hotspot/share/memory/filemap.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/memory/filemap.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -150,6 +150,7 @@
   bool   _verify_local;                 // BytecodeVerificationLocal setting
   bool   _verify_remote;                // BytecodeVerificationRemote setting
   bool   _has_platform_or_app_classes;  // Archive contains app classes
+  size_t _shared_base_address;          // SharedBaseAddress used at dump time
 
   void set_has_platform_or_app_classes(bool v) {
     _has_platform_or_app_classes = v;
@@ -263,7 +264,8 @@
                      bool read_only, bool allow_exec);
   size_t write_archive_heap_regions(GrowableArray<MemRegion> *heap_mem,
                                     GrowableArray<ArchiveHeapOopmapInfo> *oopmaps,
-                                    int first_region_id, int max_num_regions);
+                                    int first_region_id, int max_num_regions,
+                                    bool print_log);
   void  write_bytes(const void* buffer, size_t count);
   void  write_bytes_aligned(const void* buffer, size_t count);
   char* map_region(int i, char** top_ret);
--- a/src/hotspot/share/memory/heapShared.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/memory/heapShared.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -391,9 +391,7 @@
       record->init(&info);
 
       unsigned int hash = primitive_hash<Klass*>(klass);
-      uintx deltax = MetaspaceShared::object_delta(record);
-      guarantee(deltax <= MAX_SHARED_DELTA, "must not be");
-      u4 delta = u4(deltax);
+      u4 delta = MetaspaceShared::object_delta_u4(record);
       _writer->add(hash, delta);
     }
     return true; // keep on iterating
@@ -417,7 +415,7 @@
   int num_buckets = CompactHashtableWriter::default_num_buckets(d_table->_count);
   CompactHashtableWriter writer(num_buckets, &stats);
   CopyKlassSubGraphInfoToArchive copy(&writer);
-  _dump_time_subgraph_info_table->iterate(&copy);
+  d_table->iterate(&copy);
 
   writer.dump(&_run_time_subgraph_info_table, "subgraphs");
 }
@@ -433,7 +431,7 @@
   assert(!DumpSharedSpaces, "Should not be called with DumpSharedSpaces");
 
   unsigned int hash = primitive_hash<Klass*>(k);
-  ArchivedKlassSubGraphInfoRecord* record = _run_time_subgraph_info_table.lookup(k, hash, 0);
+  const ArchivedKlassSubGraphInfoRecord* record = _run_time_subgraph_info_table.lookup(k, hash, 0);
 
   // Initialize from archived data. Currently this is done only
   // during VM initialization time. No lock is needed.
--- a/src/hotspot/share/memory/heapShared.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/memory/heapShared.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -109,9 +109,9 @@
   ArchivedKlassSubGraphInfoRecord() :
     _k(NULL), _entry_field_records(NULL), _subgraph_object_klasses(NULL) {}
   void init(KlassSubGraphInfo* info);
-  Klass* klass() { return _k; }
-  Array<juint>*  entry_field_records() { return _entry_field_records; }
-  Array<Klass*>* subgraph_object_klasses() { return _subgraph_object_klasses; }
+  Klass* klass() const { return _k; }
+  Array<juint>*  entry_field_records() const { return _entry_field_records; }
+  Array<Klass*>* subgraph_object_klasses() const { return _subgraph_object_klasses; }
 };
 #endif // INCLUDE_CDS_JAVA_HEAP
 
@@ -154,18 +154,16 @@
     int _count;
   };
 
-  inline static ArchivedKlassSubGraphInfoRecord* read_record_from_compact_hashtable(address base_address, u4 offset) {
-    return (ArchivedKlassSubGraphInfoRecord*)(base_address + offset);
-  }
-
-  inline static bool record_equals_compact_hashtable_entry(ArchivedKlassSubGraphInfoRecord* value, const Klass* key, int len_unused) {
+public: // solaris compiler wants this for RunTimeKlassSubGraphInfoTable
+  inline static bool record_equals_compact_hashtable_entry(
+       const ArchivedKlassSubGraphInfoRecord* value, const Klass* key, int len_unused) {
     return (value->klass() == key);
   }
 
-  typedef CompactHashtable<
+private:
+  typedef OffsetCompactHashtable<
     const Klass*,
-    ArchivedKlassSubGraphInfoRecord*,
-    read_record_from_compact_hashtable,
+    const ArchivedKlassSubGraphInfoRecord*,
     record_equals_compact_hashtable_entry
     > RunTimeKlassSubGraphInfoTable;
 
--- a/src/hotspot/share/memory/metaspaceShared.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/memory/metaspaceShared.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -64,7 +64,6 @@
 #include "utilities/align.hpp"
 #include "utilities/bitMap.hpp"
 #include "utilities/defaultStream.hpp"
-#include "utilities/hashtable.inline.hpp"
 #if INCLUDE_G1GC
 #include "gc/g1/g1CollectedHeap.hpp"
 #endif
@@ -124,6 +123,15 @@
       MetaspaceShared::report_out_of_space(_name, newtop - _top);
       ShouldNotReachHere();
     }
+    uintx delta = MetaspaceShared::object_delta_uintx(newtop);
+    if (delta > MAX_SHARED_DELTA) {
+      // This is just a sanity check and should not appear in any real world usage. This
+      // happens only if you allocate more than 2GB of shared objects and would require
+      // millions of shared classes.
+      vm_exit_during_initialization("Out of memory in the CDS archive",
+                                    "Please reduce the number of shared classes.");
+    }
+
     MetaspaceShared::commit_shared_space_to(newtop);
     _top = newtop;
     return _top;
@@ -323,6 +331,7 @@
   }
 
   _mc_region.init(&_shared_rs);
+  SharedBaseAddress = (size_t)_shared_rs.base();
   tty->print_cr("Allocated shared space: " SIZE_FORMAT " bytes at " PTR_FORMAT,
                 _shared_rs.size(), p2i(_shared_rs.base()));
 }
@@ -338,12 +347,6 @@
       ClassLoaderExt::init_app_module_paths_start_index(header->_app_module_paths_start_index);
     }
   }
-
-  if (DumpSharedSpaces) {
-    if (SharedArchiveConfigFile) {
-      read_extra_data(SharedArchiveConfigFile, THREAD);
-    }
-  }
 }
 
 void MetaspaceShared::read_extra_data(const char* filename, TRAPS) {
@@ -422,6 +425,7 @@
   SymbolTable::serialize_shared_table_header(soc);
   StringTable::serialize_shared_table_header(soc);
   HeapShared::serialize_subgraph_info_table_header(soc);
+  SystemDictionaryShared::serialize_dictionary_headers(soc);
 
   JavaClasses::serialize_offsets(soc);
   InstanceMirrorKlass::serialize_offsets(soc);
@@ -470,13 +474,11 @@
 
 class CollectClassesClosure : public KlassClosure {
   void do_klass(Klass* k) {
-    if (!(k->is_instance_klass() && InstanceKlass::cast(k)->is_in_error_state())) {
-      if (k->is_instance_klass() && InstanceKlass::cast(k)->signers() != NULL) {
-        // Mark any class with signers and don't add to the _global_klass_objects
-        k->set_has_signer_and_not_archived();
-      } else {
-        _global_klass_objects->append_if_missing(k);
-      }
+    if (k->is_instance_klass() &&
+        SystemDictionaryShared::is_excluded_class(InstanceKlass::cast(k))) {
+      // Don't add to the _global_klass_objects
+    } else {
+      _global_klass_objects->append_if_missing(k);
     }
     if (k->is_array_klass()) {
       // Add in the array classes too
@@ -583,16 +585,6 @@
   }
 }
 
-NOT_PRODUCT(
-static void assert_not_unsafe_anonymous_class(InstanceKlass* k) {
-  assert(!(k->is_unsafe_anonymous()), "cannot archive unsafe anonymous classes");
-}
-
-// Unsafe anonymous classes are not stored inside any dictionaries.
-static void assert_no_unsafe_anonymous_classes_in_dictionaries() {
-  ClassLoaderDataGraph::dictionary_classes_do(assert_not_unsafe_anonymous_class);
-})
-
 // Objects of the Metadata types (such as Klass and ConstantPool) have C++ vtables.
 // (In GCC this is the field <Type>::_vptr, i.e., first word in the object.)
 //
@@ -1129,6 +1121,17 @@
       newtop = _ro_region.top();
     } else {
       oldtop = _rw_region.top();
+      if (ref->msotype() == MetaspaceObj::ClassType) {
+        // Save a pointer immediate in front of an InstanceKlass, so
+        // we can do a quick lookup from InstanceKlass* -> RunTimeSharedClassInfo*
+        // without building another hashtable. See RunTimeSharedClassInfo::get_for()
+        // in systemDictionaryShared.cpp.
+        Klass* klass = (Klass*)obj;
+        if (klass->is_instance_klass()) {
+          SystemDictionaryShared::validate_before_archiving(InstanceKlass::cast(klass));
+          _rw_region.allocate(sizeof(address), BytesPerWord);
+        }
+      }
       p = _rw_region.allocate(bytes, alignment);
       newtop = _rw_region.top();
     }
@@ -1138,16 +1141,6 @@
     assert(isnew, "must be");
 
     _alloc_stats->record(ref->msotype(), int(newtop - oldtop), read_only);
-    if (ref->msotype() == MetaspaceObj::SymbolType) {
-      uintx delta = MetaspaceShared::object_delta(p);
-      if (delta > MAX_SHARED_DELTA) {
-        // This is just a sanity check and should not appear in any real world usage. This
-        // happens only if you allocate more than 2GB of Symbols and would require
-        // millions of shared classes.
-        vm_exit_during_initialization("Too many Symbols in the CDS archive",
-                                      "Please reduce the number of shared classes.");
-      }
-    }
   }
 
   static address get_new_loc(MetaspaceClosure::Ref* ref) {
@@ -1287,7 +1280,7 @@
       }
     }
     FileMapInfo::metaspace_pointers_do(it);
-    SystemDictionary::classes_do(it);
+    SystemDictionaryShared::dumptime_classes_do(it);
     Universe::metaspace_pointers_do(it);
     SymbolTable::metaspace_pointers_do(it);
     vmSymbols::metaspace_pointers_do(it);
@@ -1321,9 +1314,6 @@
 
 char* VM_PopulateDumpSharedSpace::dump_read_only_tables() {
   ArchiveCompactor::OtherROAllocMark mark;
-  // Reorder the system dictionary. Moving the symbols affects
-  // how the hash table indices are calculated.
-  SystemDictionary::reorder_dictionary_for_sharing();
 
   tty->print("Removing java_mirror ... ");
   if (!HeapShared::is_heap_object_archiving_allowed()) {
@@ -1331,15 +1321,10 @@
   }
   remove_java_mirror_in_classes();
   tty->print_cr("done. ");
-  NOT_PRODUCT(SystemDictionary::verify();)
 
-  size_t buckets_bytes = SystemDictionary::count_bytes_for_buckets();
-  char* buckets_top = _ro_region.allocate(buckets_bytes, sizeof(intptr_t));
-  SystemDictionary::copy_buckets(buckets_top, _ro_region.top());
+  SystemDictionaryShared::write_to_archive();
 
-  size_t table_bytes = SystemDictionary::count_bytes_for_table();
-  char* table_top = _ro_region.allocate(table_bytes, sizeof(intptr_t));
-  SystemDictionary::copy_table(table_top, _ro_region.top());
+  char* start = _ro_region.top();
 
   // Write the other data to the output array.
   WriteClosure wc(&_ro_region);
@@ -1348,7 +1333,7 @@
   // Write the bitmaps for patching the archive heap regions
   dump_archive_heap_oopmaps();
 
-  return buckets_top;
+  return start;
 }
 
 void VM_PopulateDumpSharedSpace::doit() {
@@ -1373,14 +1358,11 @@
             "loader constraints are not saved");
   guarantee(SystemDictionary::placeholders()->number_of_entries() == 0,
           "placeholders are not saved");
-  // Revisit and implement this if we prelink method handle call sites:
-  guarantee(SystemDictionary::invoke_method_table() == NULL ||
-            SystemDictionary::invoke_method_table()->number_of_entries() == 0,
-            "invoke method table is not saved");
 
   // At this point, many classes have been loaded.
   // Gather systemDictionary classes in a global array and do everything to
   // that so we don't have to walk the SystemDictionary again.
+  SystemDictionaryShared::check_excluded_classes();
   _global_klass_objects = new GrowableArray<Klass*>(1000);
   CollectClassesClosure collect_classes;
   ClassLoaderDataGraph::loaded_classes_do(&collect_classes);
@@ -1409,21 +1391,11 @@
   rewrite_nofast_bytecodes_and_calculate_fingerprints();
   tty->print_cr("done. ");
 
-  // Move classes from platform/system dictionaries into the boot dictionary
-  SystemDictionary::combine_shared_dictionaries();
-
-  // Make sure all classes have a correct loader type.
-  ClassLoaderData::the_null_class_loader_data()->dictionary()->classes_do(MetaspaceShared::check_shared_class_loader_type);
-
   // Remove all references outside the metadata
   tty->print("Removing unshareable information ... ");
   remove_unshareable_in_classes();
   tty->print_cr("done. ");
 
-  // We don't support archiving unsafe anonymous classes. Verify that they are not stored in
-  // any dictionaries.
-  NOT_PRODUCT(assert_no_unsafe_anonymous_classes_in_dictionaries());
-
   ArchiveCompactor::initialize();
   ArchiveCompactor::copy_and_compact();
 
@@ -1472,6 +1444,7 @@
   mapinfo->set_core_spaces_size(core_spaces_size);
 
   for (int pass=1; pass<=2; pass++) {
+    bool print_archive_log = (pass==1);
     if (pass == 1) {
       // The first pass doesn't actually write the data to disk. All it
       // does is to update the fields in the mapinfo->_header.
@@ -1496,12 +1469,14 @@
                                         _closed_archive_heap_regions,
                                         _closed_archive_heap_oopmaps,
                                         MetaspaceShared::first_closed_archive_heap_region,
-                                        MetaspaceShared::max_closed_archive_heap_region);
+                                        MetaspaceShared::max_closed_archive_heap_region,
+                                        print_archive_log);
     _total_open_archive_region_size = mapinfo->write_archive_heap_regions(
                                         _open_archive_heap_regions,
                                         _open_archive_heap_oopmaps,
                                         MetaspaceShared::first_open_archive_heap_region,
-                                        MetaspaceShared::max_open_archive_heap_region);
+                                        MetaspaceShared::max_open_archive_heap_region,
+                                        print_archive_log);
   }
 
   mapinfo->close();
@@ -1614,17 +1589,6 @@
   }
 };
 
-void MetaspaceShared::check_shared_class_loader_type(InstanceKlass* ik) {
-  ResourceMark rm;
-  if (ik->shared_classpath_index() == UNREGISTERED_INDEX) {
-    guarantee(ik->loader_type() == 0,
-            "Class loader type must not be set for this class %s", ik->name()->as_C_string());
-  } else {
-    guarantee(ik->loader_type() != 0,
-            "Class loader type must be set for this class %s", ik->name()->as_C_string());
-  }
-}
-
 void MetaspaceShared::link_and_cleanup_shared_classes(TRAPS) {
   // We need to iterate because verification may cause additional classes
   // to be loaded.
@@ -1645,9 +1609,6 @@
       check_closure.reset();
       ClassLoaderDataGraph::unlocked_loaded_classes_do(&check_closure);
     } while (check_closure.made_progress());
-
-    // Unverifiable classes will not be included in the CDS archive.
-    SystemDictionary::remove_classes_in_error_state();
   }
 }
 
@@ -1705,6 +1666,12 @@
 
     log_info(cds)("Shared spaces: preloaded %d classes", class_count);
 
+    if (SharedArchiveConfigFile) {
+      tty->print_cr("Reading extra data from %s ...", SharedArchiveConfigFile);
+      read_extra_data(SharedArchiveConfigFile, THREAD);
+    }
+    tty->print_cr("Reading extra data: done.");
+
     HeapShared::init_subgraph_entry_fields(THREAD);
 
     // Rewrite and link classes
@@ -1717,10 +1684,6 @@
     link_and_cleanup_shared_classes(CATCH);
     tty->print_cr("Rewriting and linking classes: done");
 
-    SystemDictionary::clear_invoke_method_table();
-
-    SystemDictionaryShared::finalize_verification_constraints();
-
     VM_PopulateDumpSharedSpace op;
     VMThread::execute(&op);
   }
@@ -1731,36 +1694,36 @@
   ClassListParser parser(class_list_path);
   int class_count = 0;
 
-    while (parser.parse_one_line()) {
-      Klass* klass = ClassLoaderExt::load_one_class(&parser, THREAD);
-      if (HAS_PENDING_EXCEPTION) {
-        if (klass == NULL &&
-             (PENDING_EXCEPTION->klass()->name() == vmSymbols::java_lang_ClassNotFoundException())) {
-          // print a warning only when the pending exception is class not found
-          tty->print_cr("Preload Warning: Cannot find %s", parser.current_class_name());
-        }
-        CLEAR_PENDING_EXCEPTION;
+  while (parser.parse_one_line()) {
+    Klass* klass = parser.load_current_class(THREAD);
+    if (HAS_PENDING_EXCEPTION) {
+      if (klass == NULL &&
+          (PENDING_EXCEPTION->klass()->name() == vmSymbols::java_lang_ClassNotFoundException())) {
+        // print a warning only when the pending exception is class not found
+        tty->print_cr("Preload Warning: Cannot find %s", parser.current_class_name());
       }
-      if (klass != NULL) {
-        if (log_is_enabled(Trace, cds)) {
-          ResourceMark rm;
-          log_trace(cds)("Shared spaces preloaded: %s", klass->external_name());
-        }
+      CLEAR_PENDING_EXCEPTION;
+    }
+    if (klass != NULL) {
+      if (log_is_enabled(Trace, cds)) {
+        ResourceMark rm;
+        log_trace(cds)("Shared spaces preloaded: %s", klass->external_name());
+      }
 
-        if (klass->is_instance_klass()) {
-          InstanceKlass* ik = InstanceKlass::cast(klass);
+      if (klass->is_instance_klass()) {
+        InstanceKlass* ik = InstanceKlass::cast(klass);
 
-          // Link the class to cause the bytecodes to be rewritten and the
-          // cpcache to be created. The linking is done as soon as classes
-          // are loaded in order that the related data structures (klass and
-          // cpCache) are located together.
-          try_link_class(ik, THREAD);
-          guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class");
-        }
+        // Link the class to cause the bytecodes to be rewritten and the
+        // cpcache to be created. The linking is done as soon as classes
+        // are loaded in order that the related data structures (klass and
+        // cpCache) are located together.
+        try_link_class(ik, THREAD);
+        guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class");
+      }
 
-        class_count++;
-      }
+      class_count++;
     }
+  }
 
   return class_count;
 }
@@ -1994,21 +1957,6 @@
 
   // The rest of the data is now stored in the RW region
   buffer = mapinfo->read_only_tables_start();
-  int sharedDictionaryLen = *(intptr_t*)buffer;
-  buffer += sizeof(intptr_t);
-  int number_of_entries = *(intptr_t*)buffer;
-  buffer += sizeof(intptr_t);
-  SystemDictionary::set_shared_dictionary((HashtableBucket<mtClass>*)buffer,
-                                          sharedDictionaryLen,
-                                          number_of_entries);
-  buffer += sharedDictionaryLen;
-
-  // The following data are the linked list elements
-  // (HashtableEntry objects) for the shared dictionary table.
-
-  int len = *(intptr_t*)buffer;     // skip over shared dictionary entries
-  buffer += sizeof(intptr_t);
-  buffer += len;
 
   // Verify various attributes of the archive, plus initialize the
   // shared string/symbol tables
@@ -2027,7 +1975,7 @@
   if (PrintSharedArchiveAndExit) {
     if (PrintSharedDictionary) {
       tty->print_cr("\nShared classes:\n");
-      SystemDictionary::print_shared(tty);
+      SystemDictionaryShared::print_on(tty);
     }
     if (_archive_loading_failed) {
       tty->print_cr("archive is invalid");
--- a/src/hotspot/share/memory/metaspaceShared.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/memory/metaspaceShared.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -107,12 +107,19 @@
   static void post_initialize(TRAPS) NOT_CDS_RETURN;
 
   // Delta of this object from the bottom of the archive.
-  static uintx object_delta(void* obj) {
+  static uintx object_delta_uintx(void* obj) {
     assert(DumpSharedSpaces, "supported only for dumping");
     assert(shared_rs()->contains(obj), "must be");
     address base_address = address(shared_rs()->base());
-    uintx delta = address(obj) - base_address;
-    return delta;
+    uintx deltax = address(obj) - base_address;
+    return deltax;
+  }
+
+  static u4 object_delta_u4(void* obj) {
+    // offset is guaranteed to be less than MAX_SHARED_DELTA in DumpRegion::expand_top_to()
+    uintx deltax = object_delta_uintx(obj);
+    guarantee(deltax <= MAX_SHARED_DELTA, "must be 32-bit offset");
+    return (u4)deltax;
   }
 
   static void set_archive_loading_failed() {
--- a/src/hotspot/share/oops/instanceKlass.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/oops/instanceKlass.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -422,17 +422,22 @@
   _static_field_size(parser.static_field_size()),
   _nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())),
   _itable_len(parser.itable_size()),
-  _reference_type(parser.reference_type()) {
-    set_vtable_length(parser.vtable_size());
-    set_kind(kind);
-    set_access_flags(parser.access_flags());
-    set_is_unsafe_anonymous(parser.is_unsafe_anonymous());
-    set_layout_helper(Klass::instance_layout_helper(parser.layout_size(),
+  _reference_type(parser.reference_type())
+{
+  set_vtable_length(parser.vtable_size());
+  set_kind(kind);
+  set_access_flags(parser.access_flags());
+  set_is_unsafe_anonymous(parser.is_unsafe_anonymous());
+  set_layout_helper(Klass::instance_layout_helper(parser.layout_size(),
                                                     false));
 
-    assert(NULL == _methods, "underlying memory not zeroed?");
-    assert(is_instance_klass(), "is layout incorrect?");
-    assert(size_helper() == parser.layout_size(), "incorrect size_helper?");
+  assert(NULL == _methods, "underlying memory not zeroed?");
+  assert(is_instance_klass(), "is layout incorrect?");
+  assert(size_helper() == parser.layout_size(), "incorrect size_helper?");
+
+  if (DumpSharedSpaces) {
+    SystemDictionaryShared::init_dumptime_info(this);
+  }
 }
 
 void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data,
@@ -579,6 +584,10 @@
     MetadataFactory::free_metadata(loader_data, annotations());
   }
   set_annotations(NULL);
+
+  if (DumpSharedSpaces) {
+    SystemDictionaryShared::remove_dumptime_info(this);
+  }
 }
 
 bool InstanceKlass::should_be_initialized() const {
--- a/src/hotspot/share/oops/klass.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/oops/klass.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -176,8 +176,7 @@
   // Flags of the current shared class.
   u2     _shared_class_flags;
   enum {
-    _has_raw_archived_mirror = 1,
-    _has_signer_and_not_archived = 1 << 2
+    _has_raw_archived_mirror = 1
   };
 #endif
   // The _archived_mirror is set at CDS dump time pointing to the cached mirror
@@ -314,15 +313,6 @@
     CDS_ONLY(return (_shared_class_flags & _has_raw_archived_mirror) != 0;)
     NOT_CDS(return false;)
   }
-#if INCLUDE_CDS
-  void set_has_signer_and_not_archived() {
-    _shared_class_flags |= _has_signer_and_not_archived;
-  }
-  bool has_signer_and_not_archived() const {
-    assert(DumpSharedSpaces, "dump time only");
-    return (_shared_class_flags & _has_signer_and_not_archived) != 0;
-  }
-#endif // INCLUDE_CDS
 
   // Obtain the module or package for this class
   virtual ModuleEntry* module() const = 0;
--- a/src/hotspot/share/opto/loopPredicate.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/opto/loopPredicate.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -942,6 +942,15 @@
   GrowableArray<float> _freqs; // cache frequencies
   PhaseIdealLoop* _phase;
 
+  void set_rounding(int mode) {
+    // fesetround is broken on windows
+    NOT_WINDOWS(fesetround(mode);)
+  }
+
+  void check_frequency(float f) {
+    NOT_WINDOWS(assert(f <= 1 && f >= 0, "Incorrect frequency");)
+  }
+
 public:
   PathFrequency(Node* dom, PhaseIdealLoop* phase)
     : _dom(dom), _stack(0), _phase(phase) {
@@ -949,7 +958,7 @@
 
   float to(Node* n) {
     // post order walk on the CFG graph from n to _dom
-    fesetround(FE_TOWARDZERO); // make sure rounding doesn't push frequency above 1
+    set_rounding(FE_TOWARDZERO); // make sure rounding doesn't push frequency above 1
     IdealLoopTree* loop = _phase->get_loop(_dom);
     Node* c = n;
     for (;;) {
@@ -976,14 +985,14 @@
                 inner_head = inner_loop->_head->as_Loop();
                 inner_head->verify_strip_mined(1);
               }
-              fesetround(FE_UPWARD);  // make sure rounding doesn't push frequency above 1
+              set_rounding(FE_UPWARD);  // make sure rounding doesn't push frequency above 1
               float loop_exit_cnt = 0.0f;
               for (uint i = 0; i < inner_loop->_body.size(); i++) {
                 Node *n = inner_loop->_body[i];
                 float c = inner_loop->compute_profile_trip_cnt_helper(n);
                 loop_exit_cnt += c;
               }
-              fesetround(FE_TOWARDZERO);
+              set_rounding(FE_TOWARDZERO);
               float cnt = -1;
               if (n->in(0)->is_If()) {
                 IfNode* iff = n->in(0)->as_If();
@@ -1003,9 +1012,9 @@
                 cnt = p * jmp->_fcnt;
               }
               float this_exit_f = cnt > 0 ? cnt / loop_exit_cnt : 0;
-              assert(this_exit_f <= 1 && this_exit_f >= 0, "Incorrect frequency");
+              check_frequency(this_exit_f);
               f = f * this_exit_f;
-              assert(f <= 1 && f >= 0, "Incorrect frequency");
+              check_frequency(f);
             } else {
               float p = -1;
               if (n->in(0)->is_If()) {
@@ -1018,7 +1027,7 @@
                 p = n->in(0)->as_Jump()->_probs[n->as_JumpProj()->_con];
               }
               f = f * p;
-              assert(f <= 1 && f >= 0, "Incorrect frequency");
+              check_frequency(f);
             }
             _freqs.at_put_grow(n->_idx, (float)f, -1);
             _stack.pop();
@@ -1026,7 +1035,7 @@
             float prev_f = _freqs_stack.pop();
             float new_f = f;
             f = new_f + prev_f;
-            assert(f <= 1 && f >= 0, "Incorrect frequency");
+            check_frequency(f);
             uint i = _stack.index();
             if (i < n->req()) {
               c = n->in(i);
@@ -1039,8 +1048,8 @@
           }
         }
         if (_stack.size() == 0) {
-          fesetround(FE_TONEAREST);
-          assert(f >= 0 && f <= 1, "should have been computed");
+          set_rounding(FE_TONEAREST);
+          check_frequency(f);
           return f;
         }
       } else if (c->is_Loop()) {
--- a/src/hotspot/share/opto/matcher.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/opto/matcher.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -1209,7 +1209,9 @@
   // Allocate a private array of RegMasks.  These RegMasks are not shared.
   msfpt->_in_rms = NEW_RESOURCE_ARRAY( RegMask, cnt );
   // Empty them all.
-  memset( msfpt->_in_rms, 0, sizeof(RegMask)*cnt );
+  for (uint i = 0; i < cnt; i++) {
+    msfpt->_in_rms[i] = RegMask();
+  }
 
   // Do all the pre-defined non-Empty register masks
   msfpt->_in_rms[TypeFunc::ReturnAdr] = _return_addr_mask;
--- a/src/hotspot/share/runtime/arguments.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/runtime/arguments.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -2074,17 +2074,10 @@
     option_type = ++spacer; // Set both to the empty string.
   }
 
-  if (os::obsolete_option(option)) {
-    jio_fprintf(defaultStream::error_stream(),
-                "Obsolete %s%soption: %s\n", option_type, spacer,
-      option->optionString);
-    return false;
-  } else {
-    jio_fprintf(defaultStream::error_stream(),
-                "Unrecognized %s%soption: %s\n", option_type, spacer,
-      option->optionString);
-    return true;
-  }
+  jio_fprintf(defaultStream::error_stream(),
+              "Unrecognized %s%soption: %s\n", option_type, spacer,
+              option->optionString);
+  return true;
 }
 
 static const char* user_assertion_options[] = {
@@ -2649,23 +2642,7 @@
       // Obsolete in JDK 10
       JDK_Version::jdk(10).to_string(version, sizeof(version));
       warning("Ignoring option %s; support was removed in %s", option->optionString, version);
-    // -Xconcurrentio
-    } else if (match_option(option, "-Xconcurrentio")) {
-      if (FLAG_SET_CMDLINE(bool, UseLWPSynchronization, true) != JVMFlag::SUCCESS) {
-        return JNI_EINVAL;
-      }
-      if (FLAG_SET_CMDLINE(bool, BackgroundCompilation, false) != JVMFlag::SUCCESS) {
-        return JNI_EINVAL;
-      }
-      SafepointSynchronize::set_defer_thr_suspend_loop_count();
-      if (FLAG_SET_CMDLINE(bool, UseTLAB, false) != JVMFlag::SUCCESS) {
-        return JNI_EINVAL;
-      }
-      if (FLAG_SET_CMDLINE(size_t, NewSizeThreadIncrease, 16 * K) != JVMFlag::SUCCESS) {  // 20Kb per thread added to new generation
-        return JNI_EINVAL;
-      }
-
-      // -Xinternalversion
+    // -Xinternalversion
     } else if (match_option(option, "-Xinternalversion")) {
       jio_fprintf(defaultStream::output_stream(), "%s\n",
                   VM_Version::internal_vm_info_string());
--- a/src/hotspot/share/runtime/os.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/runtime/os.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -802,9 +802,6 @@
   // System loadavg support.  Returns -1 if load average cannot be obtained.
   static int loadavg(double loadavg[], int nelem);
 
-  // Hook for os specific jvm options that we don't want to abort on seeing
-  static bool obsolete_option(const JavaVMOption *option);
-
   // Amount beyond the callee frame size that we bang the stack.
   static int extra_bang_size_in_bytes();
 
--- a/src/hotspot/share/runtime/safepoint.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/runtime/safepoint.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -178,10 +178,6 @@
 
   static address safepoint_counter_addr()                  { return (address)&_safepoint_counter; }
 
-  // This method is only used for -Xconcurrentio support.
-  static void set_defer_thr_suspend_loop_count() {
-    _defer_thr_suspend_loop_count = 1;
-  }
 };
 
 // Some helper assert macros for safepoint checks.
--- a/src/hotspot/share/runtime/vmStructs.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/runtime/vmStructs.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -404,6 +404,8 @@
   /* Memory */                                                                                                                       \
   /**********/                                                                                                                       \
                                                                                                                                      \
+     static_field(MetaspaceObj,                _shared_metaspace_base,                        void*)                                 \
+     static_field(MetaspaceObj,                _shared_metaspace_top,                         void*)                                 \
   nonstatic_field(ThreadLocalAllocBuffer,      _start,                                        HeapWord*)                             \
   nonstatic_field(ThreadLocalAllocBuffer,      _top,                                          HeapWord*)                             \
   nonstatic_field(ThreadLocalAllocBuffer,      _end,                                          HeapWord*)                             \
@@ -460,7 +462,6 @@
   /* SystemDictionary */                                                                                                             \
   /********************/                                                                                                             \
                                                                                                                                      \
-     static_field(SystemDictionary,            _shared_dictionary,                            Dictionary*)                           \
      static_field(SystemDictionary,            _system_loader_lock_obj,                       oop)                                   \
      static_field(SystemDictionary,            WK_KLASS(Object_klass),                        InstanceKlass*)                        \
      static_field(SystemDictionary,            WK_KLASS(String_klass),                        InstanceKlass*)                        \
--- a/src/hotspot/share/utilities/concurrentHashTable.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/utilities/concurrentHashTable.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -472,6 +472,12 @@
   template <typename SCAN_FUNC>
   void do_scan(Thread* thread, SCAN_FUNC& scan_f);
 
+  // Visit all items with SCAN_FUNC without any protection.
+  // It will assume there is no other thread accessing this
+  // table during the safepoint. Must be called with VM thread.
+  template <typename SCAN_FUNC>
+  void do_safepoint_scan(SCAN_FUNC& scan_f);
+
   // Destroying items matching EVALUATE_FUNC, before destroying items
   // DELETE_FUNC is called, if resize lock is obtained. Else returns false.
   template <typename EVALUATE_FUNC, typename DELETE_FUNC>
--- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -1116,6 +1116,8 @@
 inline void ConcurrentHashTable<VALUE, CONFIG, F>::
   do_scan(Thread* thread, SCAN_FUNC& scan_f)
 {
+  assert(!SafepointSynchronize::is_at_safepoint(),
+         "must be outside a safepoint");
   assert(_resize_lock_owner != thread, "Re-size lock held");
   lock_resize_lock(thread);
   do_scan_locked(thread, scan_f);
@@ -1124,6 +1126,49 @@
 }
 
 template <typename VALUE, typename CONFIG, MEMFLAGS F>
+template <typename SCAN_FUNC>
+inline void ConcurrentHashTable<VALUE, CONFIG, F>::
+  do_safepoint_scan(SCAN_FUNC& scan_f)
+{
+  // We only allow this method to be used during a safepoint.
+  assert(SafepointSynchronize::is_at_safepoint(),
+         "must only be called in a safepoint");
+  assert(Thread::current()->is_VM_thread(),
+         "should be in vm thread");
+
+  // Here we skip protection,
+  // thus no other thread may use this table at the same time.
+  InternalTable* table = get_table();
+  for (size_t bucket_it = 0; bucket_it < table->_size; bucket_it++) {
+    Bucket* bucket = table->get_bucket(bucket_it);
+    // If bucket have a redirect the items will be in the new table.
+    // We must visit them there since the new table will contain any
+    // concurrent inserts done after this bucket was resized.
+    // If the bucket don't have redirect flag all items is in this table.
+    if (!bucket->have_redirect()) {
+      if(!visit_nodes(bucket, scan_f)) {
+        return;
+      }
+    } else {
+      assert(bucket->is_locked(), "Bucket must be locked.");
+    }
+  }
+  // If there is a paused resize we also need to visit the already resized items.
+  table = get_new_table();
+  if (table == NULL) {
+    return;
+  }
+  DEBUG_ONLY(if (table == POISON_PTR) { return; })
+  for (size_t bucket_it = 0; bucket_it < table->_size; bucket_it++) {
+    Bucket* bucket = table->get_bucket(bucket_it);
+    assert(!bucket->is_locked(), "Bucket must be unlocked.");
+    if (!visit_nodes(bucket, scan_f)) {
+      return;
+    }
+  }
+}
+
+template <typename VALUE, typename CONFIG, MEMFLAGS F>
 template <typename EVALUATE_FUNC, typename DELETE_FUNC>
 inline bool ConcurrentHashTable<VALUE, CONFIG, F>::
   try_bulk_delete(Thread* thread, EVALUATE_FUNC& eval_f, DELETE_FUNC& del_f)
@@ -1142,6 +1187,8 @@
 inline void ConcurrentHashTable<VALUE, CONFIG, F>::
   bulk_delete(Thread* thread, EVALUATE_FUNC& eval_f, DELETE_FUNC& del_f)
 {
+  assert(!SafepointSynchronize::is_at_safepoint(),
+         "must be outside a safepoint");
   lock_resize_lock(thread);
   do_bulk_delete_locked(thread, eval_f, del_f);
   unlock_resize_lock(thread);
--- a/src/hotspot/share/utilities/hashtable.cpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/utilities/hashtable.cpp	Wed Nov 14 17:16:44 2018 +0530
@@ -33,7 +33,6 @@
 #include "classfile/stringTable.hpp"
 #include "logging/log.hpp"
 #include "memory/allocation.inline.hpp"
-#include "memory/metaspaceShared.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/weakHandle.inline.hpp"
@@ -99,11 +98,7 @@
 
 template <MEMFLAGS F> void BasicHashtable<F>::free_buckets() {
   if (NULL != _buckets) {
-    // Don't delete the buckets in the shared space.  They aren't
-    // allocated by os::malloc
-    if (!MetaspaceShared::is_in_shared_metaspace(_buckets)) {
-       FREE_C_HEAP_ARRAY(HashtableBucket, _buckets);
-    }
+    FREE_C_HEAP_ARRAY(HashtableBucket, _buckets);
     _buckets = NULL;
   }
 }
@@ -137,47 +132,6 @@
   }
   Atomic::add(-context->_num_removed, &_number_of_entries);
 }
-// Copy the table to the shared space.
-template <MEMFLAGS F> size_t BasicHashtable<F>::count_bytes_for_table() {
-  size_t bytes = 0;
-  bytes += sizeof(intptr_t); // len
-
-  for (int i = 0; i < _table_size; ++i) {
-    for (BasicHashtableEntry<F>** p = _buckets[i].entry_addr();
-         *p != NULL;
-         p = (*p)->next_addr()) {
-      bytes += entry_size();
-    }
-  }
-
-  return bytes;
-}
-
-// Dump the hash table entries (into CDS archive)
-template <MEMFLAGS F> void BasicHashtable<F>::copy_table(char* top, char* end) {
-  assert(is_aligned(top, sizeof(intptr_t)), "bad alignment");
-  intptr_t *plen = (intptr_t*)(top);
-  top += sizeof(*plen);
-
-  int i;
-  for (i = 0; i < _table_size; ++i) {
-    for (BasicHashtableEntry<F>** p = _buckets[i].entry_addr();
-         *p != NULL;
-         p = (*p)->next_addr()) {
-      *p = (BasicHashtableEntry<F>*)memcpy(top, (void*)*p, entry_size());
-      top += entry_size();
-    }
-  }
-  *plen = (char*)(top) - (char*)plen - sizeof(*plen);
-  assert(top == end, "count_bytes_for_table is wrong");
-  // Set the shared bit.
-
-  for (i = 0; i < _table_size; ++i) {
-    for (BasicHashtableEntry<F>* p = bucket(i); p != NULL; p = p->next()) {
-      p->set_shared();
-    }
-  }
-}
 
 // For oops and Strings the size of the literal is interesting. For other types, nobody cares.
 static int literal_size(ConstantPool*) { return 0; }
@@ -297,34 +251,6 @@
   st->print_cr("Maximum bucket size     : %9d", (int)summary.maximum());
 }
 
-
-// Dump the hash table buckets.
-
-template <MEMFLAGS F> size_t BasicHashtable<F>::count_bytes_for_buckets() {
-  size_t bytes = 0;
-  bytes += sizeof(intptr_t); // len
-  bytes += sizeof(intptr_t); // _number_of_entries
-  bytes += _table_size * sizeof(HashtableBucket<F>); // the buckets
-
-  return bytes;
-}
-
-// Dump the buckets (into CDS archive)
-template <MEMFLAGS F> void BasicHashtable<F>::copy_buckets(char* top, char* end) {
-  assert(is_aligned(top, sizeof(intptr_t)), "bad alignment");
-  intptr_t len = _table_size * sizeof(HashtableBucket<F>);
-  *(intptr_t*)(top) = len;
-  top += sizeof(intptr_t);
-
-  *(intptr_t*)(top) = _number_of_entries;
-  top += sizeof(intptr_t);
-
-  _buckets = (HashtableBucket<F>*)memcpy(top, (void*)_buckets, len);
-  top += len;
-
-  assert(top == end, "count_bytes_for_buckets is wrong");
-}
-
 #ifndef PRODUCT
 template <class T> void print_literal(T l) {
   l->print();
--- a/src/hotspot/share/utilities/hashtable.hpp	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/hotspot/share/utilities/hashtable.hpp	Wed Nov 14 17:16:44 2018 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, 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
@@ -147,12 +147,6 @@
   BasicHashtable(int table_size, int entry_size,
                  HashtableBucket<F>* buckets, int number_of_entries);
 
-  // Sharing support.
-  size_t count_bytes_for_buckets();
-  size_t count_bytes_for_table();
-  void copy_buckets(char* top, char* end);
-  void copy_table(char* top, char* end);
-
   // Bucket handling
   int hash_to_index(unsigned int full_hash) const {
     int h = full_hash % _table_size;
--- a/src/java.base/share/classes/java/lang/Module.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/lang/Module.java	Wed Nov 14 17:16:44 2018 +0530
@@ -1433,7 +1433,7 @@
         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
                                          + ClassWriter.COMPUTE_FRAMES);
 
-        ClassVisitor cv = new ClassVisitor(Opcodes.ASM6, cw) {
+        ClassVisitor cv = new ClassVisitor(Opcodes.ASM7, cw) {
             @Override
             public void visit(int version,
                               int access,
--- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java	Wed Nov 14 17:16:44 2018 +0530
@@ -1629,7 +1629,7 @@
         @ForceInline
         private static byte[] newArray(long indexCoder) {
             byte coder = (byte)(indexCoder >> 32);
-            int index = ((int)indexCoder & 0x7FFFFFFF);
+            int index = (int)indexCoder;
             return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, index << coder);
         }
 
@@ -1692,30 +1692,35 @@
             // no instantiation
         }
 
-        private static class StringifierMost extends ClassValue<MethodHandle> {
-            @Override
-            protected MethodHandle computeValue(Class<?> cl) {
-                if (cl == String.class) {
-                    return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, Object.class);
-                } else if (cl == float.class) {
-                    return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, float.class);
-                } else if (cl == double.class) {
-                    return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, double.class);
-                } else if (!cl.isPrimitive()) {
-                    MethodHandle mhObject = lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, Object.class);
+        private static class ObjectStringifier {
 
-                    // We need the additional conversion here, because String.valueOf(Object) may return null.
-                    // String conversion rules in Java state we need to produce "null" String in this case.
-                    // It can be easily done with applying valueOf the second time.
-                    return MethodHandles.filterReturnValue(mhObject,
-                            mhObject.asType(MethodType.methodType(String.class, String.class)));
-                }
+            // We need some additional conversion for Objects in general, because String.valueOf(Object)
+            // may return null. String conversion rules in Java state we need to produce "null" String
+            // in this case, so we provide a customized version that deals with this problematic corner case.
+            private static String valueOf(Object value) {
+                String s;
+                return (value == null || (s = value.toString()) == null) ? "null" : s;
+            }
 
-                return null;
-            }
+            // Could have used MethodHandles.lookup() instead of Lookup.IMPL_LOOKUP, if not for the fact
+            // java.lang.invoke Lookups are explicitly forbidden to be retrieved using that API.
+            private static final MethodHandle INSTANCE =
+                    lookupStatic(Lookup.IMPL_LOOKUP, ObjectStringifier.class, "valueOf", String.class, Object.class);
+
+        }
+
+        private static class FloatStringifiers {
+            private static final MethodHandle FLOAT_INSTANCE =
+                    lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, float.class);
+
+            private static final MethodHandle DOUBLE_INSTANCE =
+                    lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, double.class);
         }
 
         private static class StringifierAny extends ClassValue<MethodHandle> {
+
+            private static final ClassValue<MethodHandle> INSTANCE = new StringifierAny();
+
             @Override
             protected MethodHandle computeValue(Class<?> cl) {
                 if (cl == byte.class || cl == short.class || cl == int.class) {
@@ -1727,7 +1732,7 @@
                 } else if (cl == long.class) {
                     return lookupStatic(MethodHandles.publicLookup(), String.class, "valueOf", String.class, long.class);
                 } else {
-                    MethodHandle mh = STRINGIFIERS_MOST.get(cl);
+                    MethodHandle mh = forMost(cl);
                     if (mh != null) {
                         return mh;
                     } else {
@@ -1737,9 +1742,6 @@
             }
         }
 
-        private static final ClassValue<MethodHandle> STRINGIFIERS_MOST = new StringifierMost();
-        private static final ClassValue<MethodHandle> STRINGIFIERS_ANY = new StringifierAny();
-
         /**
          * Returns a stringifier for references and floats/doubles only.
          * Always returns null for other primitives.
@@ -1748,7 +1750,14 @@
          * @return stringifier; null, if not available
          */
         static MethodHandle forMost(Class<?> t) {
-            return STRINGIFIERS_MOST.get(t);
+            if (!t.isPrimitive()) {
+                return ObjectStringifier.INSTANCE;
+            } else if (t == float.class) {
+                return FloatStringifiers.FLOAT_INSTANCE;
+            } else if (t == double.class) {
+                return FloatStringifiers.DOUBLE_INSTANCE;
+            }
+            return null;
         }
 
         /**
@@ -1758,7 +1767,7 @@
          * @return stringifier
          */
         static MethodHandle forAny(Class<?> t) {
-            return STRINGIFIERS_ANY.get(t);
+            return StringifierAny.INSTANCE.get(t);
         }
     }
 
--- a/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java	Wed Nov 14 17:16:44 2018 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018, 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
@@ -35,7 +35,7 @@
 class TypeConvertingMethodAdapter extends MethodVisitor {
 
     TypeConvertingMethodAdapter(MethodVisitor mv) {
-        super(Opcodes.ASM5, mv);
+        super(Opcodes.ASM7, mv);
     }
 
     private static final int NUM_WRAPPERS = Wrapper.COUNT;
--- a/src/java.base/share/classes/java/lang/ref/Reference.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/lang/ref/Reference.java	Wed Nov 14 17:16:44 2018 +0530
@@ -379,7 +379,7 @@
      * Throws {@link CloneNotSupportedException}. A {@code Reference} cannot be
      * meaningfully cloned. Construct a new {@code Reference} instead.
      *
-     * @returns never returns normally
+     * @return never returns normally
      * @throws  CloneNotSupportedException always
      *
      * @since 11
--- a/src/java.base/share/classes/java/net/CookieManager.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/CookieManager.java	Wed Nov 14 17:16:44 2018 +0530
@@ -62,7 +62,7 @@
  * <ul>
  *   <li>
  *     CookieHandler is at the core of cookie management. User can call
- *     CookieHandler.setDefault to set a concrete CookieHanlder implementation
+ *     CookieHandler.setDefault to set a concrete CookieHandler implementation
  *     to be used.
  *   </li>
  *   <li>
@@ -354,7 +354,7 @@
     private boolean shouldAcceptInternal(URI uri, HttpCookie cookie) {
         try {
             return policyCallback.shouldAccept(uri, cookie);
-        } catch (Exception ignored) { // pretect against malicious callback
+        } catch (Exception ignored) { // protect against malicious callback
             return false;
         }
     }
--- a/src/java.base/share/classes/java/net/DatagramSocket.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/DatagramSocket.java	Wed Nov 14 17:16:44 2018 +0530
@@ -304,7 +304,7 @@
     private void checkOldImpl() {
         if (impl == null)
             return;
-        // DatagramSocketImpl.peekdata() is a protected method, therefore we need to use
+        // DatagramSocketImpl.peekData() is a protected method, therefore we need to use
         // getDeclaredMethod, therefore we need permission to access the member
         try {
             AccessController.doPrivileged(
@@ -660,7 +660,7 @@
                 throw new SocketException("Socket is closed");
             checkAddress (p.getAddress(), "send");
             if (connectState == ST_NOT_CONNECTED) {
-                // check the address is ok wiht the security manager on every send.
+                // check the address is ok with the security manager on every send.
                 SecurityManager security = System.getSecurityManager();
 
                 // The reason you want to synchronize on datagram packet
@@ -1070,7 +1070,7 @@
      *
      * @param on  whether to enable or disable the
      * @exception SocketException if an error occurs enabling or
-     *            disabling the {@code SO_RESUEADDR} socket option,
+     *            disabling the {@code SO_REUSEADDR} socket option,
      *            or the socket is closed.
      * @since 1.4
      * @see #getReuseAddress()
--- a/src/java.base/share/classes/java/net/HttpCookie.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/HttpCookie.java	Wed Nov 14 17:16:44 2018 +0530
@@ -666,7 +666,7 @@
         int domainLength = domain.length();
         int lengthDiff = host.length() - domainLength;
         if (lengthDiff == 0) {
-            // if the host name and the domain name are just string-compare euqal
+            // if the host name and the domain name are just string-compare equal
             return host.equalsIgnoreCase(domain);
         }
         else if (lengthDiff > 0) {
@@ -1131,7 +1131,7 @@
      * Split cookie header string according to rfc 2965:
      *   1) split where it is a comma;
      *   2) but not the comma surrounding by double-quotes, which is the comma
-     *      inside port list or embeded URIs.
+     *      inside port list or embedded URIs.
      *
      * @param  header
      *         the cookie header string to split
--- a/src/java.base/share/classes/java/net/IDN.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/IDN.java	Wed Nov 14 17:16:44 2018 +0530
@@ -407,7 +407,7 @@
     // 26-letter Latin alphabet <A-Z a-z>, the digits <0-9>, and the hyphen
     // <->.
     // Non LDH refers to characters in the ASCII range, but which are not
-    // letters, digits or the hypen.
+    // letters, digits or the hyphen.
     //
     // non-LDH = 0..0x2C, 0x2E..0x2F, 0x3A..0x40, 0x5B..0x60, 0x7B..0x7F
     //
--- a/src/java.base/share/classes/java/net/InMemoryCookieStore.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/InMemoryCookieStore.java	Wed Nov 14 17:16:44 2018 +0530
@@ -54,7 +54,7 @@
     private Map<String, List<HttpCookie>> domainIndex = null;
     private Map<URI, List<HttpCookie>> uriIndex = null;
 
-    // use ReentrantLock instead of syncronized for scalability
+    // use ReentrantLock instead of synchronized for scalability
     private ReentrantLock lock = null;
 
 
@@ -260,7 +260,7 @@
         int domainLength = domain.length();
         int lengthDiff = host.length() - domainLength;
         if (lengthDiff == 0) {
-            // if the host name and the domain name are just string-compare euqal
+            // if the host name and the domain name are just string-compare equal
             return host.equalsIgnoreCase(domain);
         } else if (lengthDiff > 0) {
             // need to check H & D component
@@ -301,7 +301,7 @@
                             toRemove.add(c);
                         }
                     } else {
-                        // the cookie has beed removed from main store,
+                        // the cookie has been removed from main store,
                         // so also remove it from domain indexed store
                         toRemove.add(c);
                     }
@@ -345,7 +345,7 @@
                                 cookieJar.remove(ck);
                             }
                         } else {
-                            // the cookie has beed removed from main store,
+                            // the cookie has been removed from main store,
                             // so also remove it from domain indexed store
                             it.remove();
                         }
--- a/src/java.base/share/classes/java/net/Inet4Address.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/Inet4Address.java	Wed Nov 14 17:16:44 2018 +0530
@@ -164,7 +164,7 @@
 
     /**
      * Utility routine to check if the InetAddress is a wildcard address.
-     * @return a {@code boolean} indicating if the Inetaddress is
+     * @return a {@code boolean} indicating if the InetAddress is
      *         a wildcard address.
      */
     public boolean isAnyLocalAddress() {
--- a/src/java.base/share/classes/java/net/Inet6Address.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/Inet6Address.java	Wed Nov 14 17:16:44 2018 +0530
@@ -415,7 +415,7 @@
      * set to the value corresponding to the given interface for the address
      * type specified in {@code addr}. The call will fail with an
      * UnknownHostException if the given interface does not have a numeric
-     * scope_id assigned for the given address type (eg. link-local or site-local).
+     * scope_id assigned for the given address type (e.g. link-local or site-local).
      * See <a href="Inet6Address.html#scoped">here</a> for a description of IPv6
      * scoped addresses.
      *
@@ -507,7 +507,7 @@
 
     /* check the two Ipv6 addresses and return false if they are both
      * non global address types, but not the same.
-     * (ie. one is sitelocal and the other linklocal)
+     * (i.e. one is site-local and the other link-local)
      * return true otherwise.
      */
 
@@ -683,7 +683,7 @@
     /**
      * Utility routine to check if the InetAddress is a wildcard address.
      *
-     * @return a {@code boolean} indicating if the Inetaddress is
+     * @return a {@code boolean} indicating if the InetAddress is
      *         a wildcard address.
      */
     @Override
@@ -821,7 +821,7 @@
 
     /**
      * Returns the scoped interface, if this instance was created with
-     * with a scoped interface.
+     * a scoped interface.
      *
      * @return the scoped interface, or null if not set.
      * @since 1.5
--- a/src/java.base/share/classes/java/net/InetAddress.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/InetAddress.java	Wed Nov 14 17:16:44 2018 +0530
@@ -377,7 +377,7 @@
 
     /**
      * Utility routine to check if the InetAddress is a wildcard address.
-     * @return a {@code boolean} indicating if the Inetaddress is
+     * @return a {@code boolean} indicating if the InetAddress is
      *         a wildcard address.
      * @since 1.4
      */
@@ -1022,7 +1022,7 @@
          * <p>Lookup a host mapping by name. Retrieve the IP addresses
          * associated with a host.
          *
-         * <p>Search the configured hosts file for the addresses assocaited with
+         * <p>Search the configured hosts file for the addresses associated
          * with the specified host name.
          *
          * @param host the specified hostname
@@ -1038,7 +1038,7 @@
             byte addr[] = new byte[4];
             ArrayList<InetAddress> inetAddresses = null;
 
-            // lookup the file and create a list InetAddress for the specfied host
+            // lookup the file and create a list InetAddress for the specified host
             try (Scanner hostsFileScanner = new Scanner(new File(hostsFile), "UTF-8")) {
                 while (hostsFileScanner.hasNextLine()) {
                     hostEntry = hostsFileScanner.nextLine();
@@ -1341,7 +1341,7 @@
                     throw new UnknownHostException(host + ": invalid IPv6 address");
                 }
             } else if (ipv6Expected) {
-                // Means an IPv4 litteral between brackets!
+                // Means an IPv4 literal between brackets!
                 throw new UnknownHostException("["+host+"]");
             }
             InetAddress[] ret = new InetAddress[1];
@@ -1358,7 +1358,7 @@
                 return ret;
             }
         } else if (ipv6Expected) {
-            // We were expecting an IPv6 Litteral, but got something else
+            // We were expecting an IPv6 Literal, but got something else
             throw new UnknownHostException("["+host+"]");
         }
         return getAllByName0(host, reqAddr, true, true);
--- a/src/java.base/share/classes/java/net/NetworkInterface.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/NetworkInterface.java	Wed Nov 14 17:16:44 2018 +0530
@@ -170,7 +170,7 @@
      * a SecurityException will be returned in the List.
      *
      * @return a {@code List} object with all or a subset of the
-     *         InterfaceAddresss of this network interface
+     *         InterfaceAddress of this network interface
      * @since 1.6
      */
     public java.util.List<InterfaceAddress> getInterfaceAddresses() {
--- a/src/java.base/share/classes/java/net/ProxySelector.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/ProxySelector.java	Wed Nov 14 17:16:44 2018 +0530
@@ -136,7 +136,7 @@
      * @param   uri
      *          The URI that a connection is required to
      *
-     * @return  a List of Proxies. Each element in the
+     * @return  a List of Proxies. Each element in
      *          the List is of type
      *          {@link java.net.Proxy Proxy};
      *          when no proxy is available, the list will
--- a/src/java.base/share/classes/java/net/ResponseCache.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/ResponseCache.java	Wed Nov 14 17:16:44 2018 +0530
@@ -91,7 +91,7 @@
     /**
      * Sets (or unsets) the system-wide cache.
      *
-     * Note: non-standard procotol handlers may ignore this setting.
+     * Note: non-standard protocol handlers may ignore this setting.
      *
      * @param responseCache The response cache, or
      *          {@code null} to unset the cache.
--- a/src/java.base/share/classes/java/net/SecureCacheResponse.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/SecureCacheResponse.java	Wed Nov 14 17:16:44 2018 +0530
@@ -82,7 +82,7 @@
      * retrieved the network resource.
      *
      * @return the server's principal. Returns an X500Principal of the
-     * end-entity certiticate for X509-based cipher suites, and
+     * end-entity certificate for X509-based cipher suites, and
      * KerberosPrincipal for Kerberos cipher suites.
      *
      * @throws SSLPeerUnverifiedException if the peer was not verified.
--- a/src/java.base/share/classes/java/net/ServerSocket.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/ServerSocket.java	Wed Nov 14 17:16:44 2018 +0530
@@ -166,7 +166,7 @@
      * The {@code backlog} argument is the requested maximum number of
      * pending connections on the socket. Its exact semantics are implementation
      * specific. In particular, an implementation may impose a maximum length
-     * or may choose to ignore the parameter altogther. The value provided
+     * or may choose to ignore the parameter altogether. The value provided
      * should be greater than {@code 0}. If it is less than or equal to
      * {@code 0}, then an implementation specific default will be used.
      *
@@ -214,7 +214,7 @@
      * The {@code backlog} argument is the requested maximum number of
      * pending connections on the socket. Its exact semantics are implementation
      * specific. In particular, an implementation may impose a maximum length
-     * or may choose to ignore the parameter altogther. The value provided
+     * or may choose to ignore the parameter altogether. The value provided
      * should be greater than {@code 0}. If it is less than or equal to
      * {@code 0}, then an implementation specific default will be used.
      *
@@ -351,7 +351,7 @@
      * The {@code backlog} argument is the requested maximum number of
      * pending connections on the socket. Its exact semantics are implementation
      * specific. In particular, an implementation may impose a maximum length
-     * or may choose to ignore the parameter altogther. The value provided
+     * or may choose to ignore the parameter altogether. The value provided
      * should be greater than {@code 0}. If it is less than or equal to
      * {@code 0}, then an implementation specific default will be used.
      * @param   endpoint        The IP address and port number to bind to.
@@ -826,7 +826,7 @@
      * <p>
      * The value of {@link SocketOptions#SO_RCVBUF SO_RCVBUF} is used both to
      * set the size of the internal socket receive buffer, and to set the size
-     * of the TCP receive window that is advertized to the remote peer.
+     * of the TCP receive window that is advertised to the remote peer.
      * <p>
      * It is possible to change the value subsequently, by calling
      * {@link Socket#setReceiveBufferSize(int)}. However, if the application
--- a/src/java.base/share/classes/java/net/Socket.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/Socket.java	Wed Nov 14 17:16:44 2018 +0530
@@ -1237,7 +1237,7 @@
      * should call {@link #getReceiveBufferSize()}.
      *
      * <p>The value of {@link SocketOptions#SO_RCVBUF SO_RCVBUF} is also used
-     * to set the TCP receive window that is advertized to the remote peer.
+     * to set the TCP receive window that is advertised to the remote peer.
      * Generally, the window size can be modified at any time when a socket is
      * connected. However, if a receive window larger than 64K is required then
      * this must be requested <B>before</B> the socket is connected to the
@@ -1578,10 +1578,10 @@
      * <p>
      * Note: Closing a socket doesn't clear its connection state, which means
      * this method will return {@code true} for a closed socket
-     * (see {@link #isClosed()}) if it was successfuly connected prior
+     * (see {@link #isClosed()}) if it was successfully connected prior
      * to being closed.
      *
-     * @return true if the socket was successfuly connected to a server
+     * @return true if the socket was successfully connected to a server
      * @since 1.4
      */
     public boolean isConnected() {
@@ -1594,10 +1594,10 @@
      * <p>
      * Note: Closing a socket doesn't clear its binding state, which means
      * this method will return {@code true} for a closed socket
-     * (see {@link #isClosed()}) if it was successfuly bound prior
+     * (see {@link #isClosed()}) if it was successfully bound prior
      * to being closed.
      *
-     * @return true if the socket was successfuly bound to an address
+     * @return true if the socket was successfully bound to an address
      * @since 1.4
      * @see #bind
      */
--- a/src/java.base/share/classes/java/net/SocketOutputStream.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/SocketOutputStream.java	Wed Nov 14 17:16:44 2018 +0530
@@ -51,7 +51,7 @@
      * Creates a new SocketOutputStream. Can only be called
      * by a Socket. This method needs to hang on to the owner Socket so
      * that the fd will not be closed.
-     * @param impl the socket output stream inplemented
+     * @param impl the socket output stream implemented
      */
     SocketOutputStream(AbstractPlainSocketImpl impl) throws IOException {
         super(impl.getFileDescriptor());
--- a/src/java.base/share/classes/java/net/SocketPermission.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/SocketPermission.java	Wed Nov 14 17:16:44 2018 +0530
@@ -283,7 +283,7 @@
      *    nr = new SocketPermission("204.160.241.0:1024-65535", "connect");
      * </pre>
      *
-     * @param host the hostname or IPaddress of the computer, optionally
+     * @param host the hostname or IP address of the computer, optionally
      * including a colon followed by a port or port range.
      * @param action the action string.
      */
@@ -317,7 +317,7 @@
                 if ((ind = host.indexOf(':')) != host.lastIndexOf(':')) {
                     /* More than one ":", meaning IPv6 address is not
                      * in RFC 2732 format;
-                     * We will rectify user errors for all unambiguious cases
+                     * We will rectify user errors for all unambiguous cases
                      */
                     StringTokenizer st = new StringTokenizer(host, ":");
                     int tokens = st.countTokens();
@@ -961,7 +961,7 @@
                 return (that.cname.endsWith(this.cname));
             }
 
-            // comapare IP addresses
+            // compare IP addresses
             if (this.addresses == null) {
                 this.getIP();
             }
--- a/src/java.base/share/classes/java/net/SocksSocketImpl.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/SocksSocketImpl.java	Wed Nov 14 17:16:44 2018 +0530
@@ -51,7 +51,7 @@
     private Socket cmdsock = null;
     private InputStream cmdIn = null;
     private OutputStream cmdOut = null;
-    /* true if the Proxy has been set programatically */
+    /* true if the Proxy has been set programmatically */
     private boolean applicationSetProxy;  /* false */
 
 
@@ -145,7 +145,7 @@
     }
 
     /**
-     * Provides the authentication machanism required by the proxy.
+     * Provides the authentication mechanism required by the proxy.
      */
     private boolean authenticate(byte method, InputStream in,
                                  BufferedOutputStream out) throws IOException {
@@ -158,7 +158,7 @@
         // No Authentication required. We're done then!
         if (method == NO_AUTH)
             return true;
-        /**
+        /*
          * User/Password authentication. Try, in that order :
          * - The application provided Authenticator, if any
          * - the user.name & no password (backward compatibility behavior).
@@ -377,7 +377,7 @@
             URI uri;
             // Use getHostString() to avoid reverse lookups
             String host = epoint.getHostString();
-            // IPv6 litteral?
+            // IPv6 literal?
             if (epoint.getAddress() instanceof Inet6Address &&
                 (!host.startsWith("[")) && (host.indexOf(':') >= 0)) {
                 host = "[" + host + "]";
@@ -692,7 +692,7 @@
             URI uri;
             // Use getHostString() to avoid reverse lookups
             String host = saddr.getHostString();
-            // IPv6 litteral?
+            // IPv6 literal?
             if (saddr.getAddress() instanceof Inet6Address &&
                 (!host.startsWith("[")) && (host.indexOf(':') >= 0)) {
                 host = "[" + host + "]";
--- a/src/java.base/share/classes/java/net/URI.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/URI.java	Wed Nov 14 17:16:44 2018 +0530
@@ -861,9 +861,9 @@
      *
      * <p> This method is provided for use in situations where it is known that
      * the given string is a legal URI, for example for URI constants declared
-     * within in a program, and so it would be considered a programming error
+     * within a program, and so it would be considered a programming error
      * for the string not to parse as such.  The constructors, which throw
-     * {@link URISyntaxException} directly, should be used situations where a
+     * {@link URISyntaxException} directly, should be used in situations where a
      * URI is being constructed from user input or from some other source that
      * may be prone to errors.  </p>
      *
--- a/src/java.base/share/classes/java/net/URL.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/URL.java	Wed Nov 14 17:16:44 2018 +0530
@@ -1009,7 +1009,7 @@
      * can not be converted to a URI.
      *
      * @exception URISyntaxException if this URL is not formatted strictly according to
-     *            to RFC2396 and cannot be converted to a URI.
+     *            RFC2396 and cannot be converted to a URI.
      *
      * @return    a URI instance equivalent to this URL.
      * @since 1.5
@@ -1054,7 +1054,7 @@
     /**
      * Same as {@link #openConnection()}, except that the connection will be
      * made through the specified proxy; Protocol handlers that do not
-     * support proxing will ignore the proxy parameter and make a
+     * support proxying will ignore the proxy parameter and make a
      * normal connection.
      *
      * Invoking this method preempts the system's default
--- a/src/java.base/share/classes/java/net/URLEncoder.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/URLEncoder.java	Wed Nov 14 17:16:44 2018 +0530
@@ -109,7 +109,7 @@
          * list. It is also noteworthy that this is consistent with
          * O'Reilly's "HTML: The Definitive Guide" (page 164).
          *
-         * As a last note, Intenet Explorer does not encode the "@"
+         * As a last note, Internet Explorer does not encode the "@"
          * character which is clearly not unreserved according to the
          * RFC. We are being consistent with the RFC in this matter,
          * as is Netscape.
--- a/src/java.base/share/classes/java/net/URLPermission.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/URLPermission.java	Wed Nov 14 17:16:44 2018 +0530
@@ -51,7 +51,7 @@
  *     portrange = portnumber | -portnumber | portnumber-[portnumber] | *
  *     hostrange = ([*.] dnsname) | IPv4address | IPv6address
  * </pre>
- * <i>dnsname</i> is a standard DNS host or domain name, ie. one or more labels
+ * <i>dnsname</i> is a standard DNS host or domain name, i.e. one or more labels
  * separated by ".". <i>IPv4address</i> is a standard literal IPv4 address and
  * <i>IPv6address</i> is as defined in <a href="http://www.ietf.org/rfc/rfc2732.txt">
  * RFC 2732</a>. Literal IPv6 addresses must however, be enclosed in '[]' characters.
@@ -89,7 +89,7 @@
  * </tr>
  * <tr><th scope="row">http://www.oracle.com/a/b/-</th>
  *   <td>The '-' character refers to all resources recursively below the
- *       preceding path (eg. http://www.oracle.com/a/b/c/d/e.html matches this
+ *       preceding path (e.g. http://www.oracle.com/a/b/c/d/e.html matches this
  *       example).
  *   </td>
  * </tr>
--- a/src/java.base/share/classes/java/net/URLStreamHandler.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/URLStreamHandler.java	Wed Nov 14 17:16:44 2018 +0530
@@ -250,15 +250,15 @@
             } else if (path != null && path.length() > 0) {
                 isRelPath = true;
                 int ind = path.lastIndexOf('/');
-                String seperator = "";
+                String separator = "";
                 if (ind == -1 && authority != null)
-                    seperator = "/";
-                path = path.substring(0, ind + 1) + seperator +
+                    separator = "/";
+                path = path.substring(0, ind + 1) + separator +
                          spec.substring(start, limit);
 
             } else {
-                String seperator = (authority != null) ? "/" : "";
-                path = seperator + spec.substring(start, limit);
+                String separator = (authority != null) ? "/" : "";
+                path = separator + spec.substring(start, limit);
             }
         } else if (queryOnly && path != null) {
             int ind = path.lastIndexOf('/');
@@ -314,7 +314,7 @@
 
     /**
      * Returns the default port for a URL parsed by this handler. This method
-     * is meant to be overidden by handlers with default port numbers.
+     * is meant to be overridden by handlers with default port numbers.
      * @return the default port for a {@code URL} parsed by this handler.
      * @since 1.3
      */
@@ -323,14 +323,14 @@
     }
 
     /**
-     * Provides the default equals calculation. May be overidden by handlers
+     * Provides the default equals calculation. May be overridden by handlers
      * for other protocols that have different requirements for equals().
      * This method requires that none of its arguments is null. This is
      * guaranteed by the fact that it is only called by java.net.URL class.
      * @param u1 a URL object
      * @param u2 a URL object
      * @return {@code true} if the two urls are
-     * considered equal, ie. they refer to the same
+     * considered equal, i.e. they refer to the same
      * fragment in the same file.
      * @since 1.3
      */
@@ -342,7 +342,7 @@
     }
 
     /**
-     * Provides the default hash calculation. May be overidden by handlers for
+     * Provides the default hash calculation. May be overridden by handlers for
      * other protocols that have different requirements for hashCode
      * calculation.
      * @param u a URL object
--- a/src/java.base/share/classes/java/net/spi/URLStreamHandlerProvider.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/net/spi/URLStreamHandlerProvider.java	Wed Nov 14 17:16:44 2018 +0530
@@ -30,7 +30,7 @@
 /**
  * URL stream handler service-provider class.
  *
- *<p> A URL stream handler provider is a concrete subclass of this class that
+ * <p> A URL stream handler provider is a concrete subclass of this class that
  * has a zero-argument constructor. URL stream handler providers may be
  * installed in an instance of the Java platform by adding them to the
  * application class path.
--- a/src/java.base/share/classes/java/nio/channels/MulticastChannel.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/java/nio/channels/MulticastChannel.java	Wed Nov 14 17:16:44 2018 +0530
@@ -177,7 +177,7 @@
      * @throws  SecurityException
      *          If a security manager is set, and its
      *          {@link SecurityManager#checkMulticast(InetAddress) checkMulticast}
-     *          method denies access to the multiast group
+     *          method denies access to the multicast group
      */
     MembershipKey join(InetAddress group, NetworkInterface interf)
         throws IOException;
@@ -226,7 +226,7 @@
      * @throws  SecurityException
      *          If a security manager is set, and its
      *          {@link SecurityManager#checkMulticast(InetAddress) checkMulticast}
-     *          method denies access to the multiast group
+     *          method denies access to the multicast group
      */
     MembershipKey join(InetAddress group, NetworkInterface interf, InetAddress source)
         throws IOException;
--- a/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Wed Nov 14 17:16:44 2018 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, 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
@@ -153,7 +153,7 @@
 
         ClassReader cr = new ClassReader(in);
 
-        ClassVisitor cv = new ClassVisitor(Opcodes.ASM6, cw) {
+        ClassVisitor cv = new ClassVisitor(Opcodes.ASM7, cw) {
             @Override
             public ModuleVisitor visitModule(String name, int flags, String version) {
                 Version v = ModuleInfoExtender.this.version;
@@ -170,7 +170,7 @@
                     packages.forEach(pn -> mv.visitPackage(pn.replace('.', '/')));
                 }
 
-                return new ModuleVisitor(Opcodes.ASM6, mv) {
+                return new ModuleVisitor(Opcodes.ASM7, mv) {
                     public void visitMainClass(String existingMainClass) {
                         // skip main class if there is a new value
                         if (mainClass == null) {
--- a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/AnnotationVisitor.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/AnnotationVisitor.java	Wed Nov 14 17:16:44 2018 +0530
@@ -59,9 +59,9 @@
 package jdk.internal.org.objectweb.asm;
 
 /**
- * A visitor to visit a Java annotation. The methods of this class must be
- * called in the following order: ( <tt>visit</tt> | <tt>visitEnum</tt> |
- * <tt>visitAnnotation</tt> | <tt>visitArray</tt> )* <tt>visitEnd</tt>.
+ * A visitor to visit a Java annotation. The methods of this class must be called in the following
+ * order: ( {@code visit} | {@code visitEnum} | {@code visitAnnotation} | {@code visitArray} )*
+ * {@code visitEnd}.
  *
  * @author Eric Bruneton
  * @author Eugene Kuleshov
@@ -69,127 +69,105 @@
 public abstract class AnnotationVisitor {
 
     /**
-     * The ASM API version implemented by this visitor. The value of this field
-     * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
+      * The ASM API version implemented by this visitor. The value of this field must be one of {@link
+      * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+      */
     protected final int api;
 
-    /**
-     * The annotation visitor to which this visitor must delegate method calls.
-     * May be null.
-     */
+    /** The annotation visitor to which this visitor must delegate method calls. May be null. */
     protected AnnotationVisitor av;
 
     /**
-     * Constructs a new {@link AnnotationVisitor}.
-     *
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     */
+      * Constructs a new {@link AnnotationVisitor}.
+      *
+      * @param api the ASM API version implemented by this visitor. Must be one of {@link
+      *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+      */
     public AnnotationVisitor(final int api) {
         this(api, null);
     }
 
     /**
-     * Constructs a new {@link AnnotationVisitor}.
-     *
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     * @param av
-     *            the annotation visitor to which this visitor must delegate
-     *            method calls. May be null.
-     */
-    public AnnotationVisitor(final int api, final AnnotationVisitor av) {
-        if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
+      * Constructs a new {@link AnnotationVisitor}.
+      *
+      * @param api the ASM API version implemented by this visitor. Must be one of {@link
+      *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+      * @param annotationVisitor the annotation visitor to which this visitor must delegate method
+      *     calls. May be null.
+      */
+    public AnnotationVisitor(final int api, final AnnotationVisitor annotationVisitor) {
+        if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
             throw new IllegalArgumentException();
         }
         this.api = api;
-        this.av = av;
+        this.av = annotationVisitor;
     }
 
     /**
-     * Visits a primitive value of the annotation.
-     *
-     * @param name
-     *            the value name.
-     * @param value
-     *            the actual value, whose type must be {@link Byte},
-     *            {@link Boolean}, {@link Character}, {@link Short},
-     *            {@link Integer} , {@link Long}, {@link Float}, {@link Double},
-     *            {@link String} or {@link Type} of OBJECT or ARRAY sort. This
-     *            value can also be an array of byte, boolean, short, char, int,
-     *            long, float or double values (this is equivalent to using
-     *            {@link #visitArray visitArray} and visiting each array element
-     *            in turn, but is more convenient).
-     */
-    public void visit(String name, Object value) {
+      * Visits a primitive value of the annotation.
+      *
+      * @param name the value name.
+      * @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link
+      *     Character}, {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double},
+      *     {@link String} or {@link Type} of {@link Type#OBJECT} or {@link Type#ARRAY} sort. This
+      *     value can also be an array of byte, boolean, short, char, int, long, float or double values
+      *     (this is equivalent to using {@link #visitArray} and visiting each array element in turn,
+      *     but is more convenient).
+      */
+    public void visit(final String name, final Object value) {
         if (av != null) {
             av.visit(name, value);
         }
     }
 
     /**
-     * Visits an enumeration value of the annotation.
-     *
-     * @param name
-     *            the value name.
-     * @param desc
-     *            the class descriptor of the enumeration class.
-     * @param value
-     *            the actual enumeration value.
-     */
-    public void visitEnum(String name, String desc, String value) {
+      * Visits an enumeration value of the annotation.
+      *
+      * @param name the value name.
+      * @param descriptor the class descriptor of the enumeration class.
+      * @param value the actual enumeration value.
+      */
+    public void visitEnum(final String name, final String descriptor, final String value) {
         if (av != null) {
-            av.visitEnum(name, desc, value);
+            av.visitEnum(name, descriptor, value);
         }
     }
 
     /**
-     * Visits a nested annotation value of the annotation.
-     *
-     * @param name
-     *            the value name.
-     * @param desc
-     *            the class descriptor of the nested annotation class.
-     * @return a visitor to visit the actual nested annotation value, or
-     *         <tt>null</tt> if this visitor is not interested in visiting this
-     *         nested annotation. <i>The nested annotation value must be fully
-     *         visited before calling other methods on this annotation
-     *         visitor</i>.
-     */
-    public AnnotationVisitor visitAnnotation(String name, String desc) {
+      * Visits a nested annotation value of the annotation.
+      *
+      * @param name the value name.
+      * @param descriptor the class descriptor of the nested annotation class.
+      * @return a visitor to visit the actual nested annotation value, or {@literal null} if this
+      *     visitor is not interested in visiting this nested annotation. <i>The nested annotation
+      *     value must be fully visited before calling other methods on this annotation visitor</i>.
+      */
+    public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
         if (av != null) {
-            return av.visitAnnotation(name, desc);
+            return av.visitAnnotation(name, descriptor);
         }
         return null;
     }
 
     /**
-     * Visits an array value of the annotation. Note that arrays of primitive
-     * types (such as byte, boolean, short, char, int, long, float or double)
-     * can be passed as value to {@link #visit visit}. This is what
-     * {@link ClassReader} does.
-     *
-     * @param name
-     *            the value name.
-     * @return a visitor to visit the actual array value elements, or
-     *         <tt>null</tt> if this visitor is not interested in visiting these
-     *         values. The 'name' parameters passed to the methods of this
-     *         visitor are ignored. <i>All the array values must be visited
-     *         before calling other methods on this annotation visitor</i>.
-     */
-    public AnnotationVisitor visitArray(String name) {
+      * Visits an array value of the annotation. Note that arrays of primitive types (such as byte,
+      * boolean, short, char, int, long, float or double) can be passed as value to {@link #visit
+      * visit}. This is what {@link ClassReader} does.
+      *
+      * @param name the value name.
+      * @return a visitor to visit the actual array value elements, or {@literal null} if this visitor
+      *     is not interested in visiting these values. The 'name' parameters passed to the methods of
+      *     this visitor are ignored. <i>All the array values must be visited before calling other
+      *     methods on this annotation visitor</i>.
+      */
+    public AnnotationVisitor visitArray(final String name) {
         if (av != null) {
             return av.visitArray(name);
         }
         return null;
     }
 
-    /**
-     * Visits the end of the annotation.
-     */
+    /** Visits the end of the annotation. */
     public void visitEnd() {
         if (av != null) {
             av.visitEnd();
--- a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/AnnotationWriter.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/AnnotationWriter.java	Wed Nov 14 17:16:44 2018 +0530
@@ -59,342 +59,391 @@
 package jdk.internal.org.objectweb.asm;
 
 /**
- * An {@link AnnotationVisitor} that generates annotations in bytecode form.
+ * An {@link AnnotationVisitor} that generates a corresponding 'annotation' or 'type_annotation'
+ * structure, as defined in the Java Virtual Machine Specification (JVMS). AnnotationWriter
+ * instances can be chained in a doubly linked list, from which Runtime[In]Visible[Type]Annotations
+ * attributes can be generated with the {@link #putAnnotations} method. Similarly, arrays of such
+ * lists can be used to generate Runtime[In]VisibleParameterAnnotations attributes.
  *
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16">JVMS
+ *     4.7.16</a>
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20">JVMS
+ *     4.7.20</a>
  * @author Eric Bruneton
  * @author Eugene Kuleshov
  */
 final class AnnotationWriter extends AnnotationVisitor {
 
-    /**
-     * The class writer to which this annotation must be added.
-     */
-    private final ClassWriter cw;
+    /** Where the constants used in this AnnotationWriter must be stored. */
+    private final SymbolTable symbolTable;
 
     /**
-     * The number of values in this annotation.
-     */
-    private int size;
+      * Whether values are named or not. AnnotationWriter instances used for annotation default and
+      * annotation arrays use unnamed values (i.e. they generate an 'element_value' structure for each
+      * value, instead of an element_name_index followed by an element_value).
+      */
+    private final boolean useNamedValues;
 
     /**
-     * <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation
-     * writers used for annotation default and annotation arrays use unnamed
-     * values.
-     */
-    private final boolean named;
+      * The 'annotation' or 'type_annotation' JVMS structure corresponding to the annotation values
+      * visited so far. All the fields of these structures, except the last one - the
+      * element_value_pairs array, must be set before this ByteVector is passed to the constructor
+      * (num_element_value_pairs can be set to 0, it is reset to the correct value in {@link
+      * #visitEnd()}). The element_value_pairs array is filled incrementally in the various visit()
+      * methods.
+      *
+      * <p>Note: as an exception to the above rules, for AnnotationDefault attributes (which contain a
+      * single element_value by definition), this ByteVector is initially empty when passed to the
+      * constructor, and {@link #numElementValuePairsOffset} is set to -1.
+      */
+    private final ByteVector annotation;
 
     /**
-     * The annotation values in bytecode form. This byte vector only contains
-     * the values themselves, i.e. the number of values must be stored as a
-     * unsigned short just before these bytes.
-     */
-    private final ByteVector bv;
+      * The offset in {@link #annotation} where {@link #numElementValuePairs} must be stored (or -1 for
+      * the case of AnnotationDefault attributes).
+      */
+    private final int numElementValuePairsOffset;
+
+    /** The number of element value pairs visited so far. */
+    private int numElementValuePairs;
 
     /**
-     * The byte vector to be used to store the number of values of this
-     * annotation. See {@link #bv}.
-     */
-    private final ByteVector parent;
+      * The previous AnnotationWriter. This field is used to store the list of annotations of a
+      * Runtime[In]Visible[Type]Annotations attribute. It is unused for nested or array annotations
+      * (annotation values of annotation type), or for AnnotationDefault attributes.
+      */
+    private final AnnotationWriter previousAnnotation;
 
     /**
-     * Where the number of values of this annotation must be stored in
-     * {@link #parent}.
-     */
-    private final int offset;
+      * The next AnnotationWriter. This field is used to store the list of annotations of a
+      * Runtime[In]Visible[Type]Annotations attribute. It is unused for nested or array annotations
+      * (annotation values of annotation type), or for AnnotationDefault attributes.
+      */
+    private AnnotationWriter nextAnnotation;
+
+    // -----------------------------------------------------------------------------------------------
+    // Constructors
+    // -----------------------------------------------------------------------------------------------
 
     /**
-     * Next annotation writer. This field is used to store annotation lists.
-     */
-    AnnotationWriter next;
+      * Constructs a new {@link AnnotationWriter}.
+      *
+      * @param symbolTable where the constants used in this AnnotationWriter must be stored.
+      * @param useNamedValues whether values are named or not. AnnotationDefault and annotation arrays
+      *     use unnamed values.
+      * @param annotation where the 'annotation' or 'type_annotation' JVMS structure corresponding to
+      *     the visited content must be stored. This ByteVector must already contain all the fields of
+      *     the structure except the last one (the element_value_pairs array).
+      * @param previousAnnotation the previously visited annotation of the
+      *     Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in
+      *     other cases (e.g. nested or array annotations).
+      */
+    AnnotationWriter(
+            final SymbolTable symbolTable,
+            final boolean useNamedValues,
+            final ByteVector annotation,
+            final AnnotationWriter previousAnnotation) {
+        super(Opcodes.ASM7);
+        this.symbolTable = symbolTable;
+        this.useNamedValues = useNamedValues;
+        this.annotation = annotation;
+        // By hypothesis, num_element_value_pairs is stored in the last unsigned short of 'annotation'.
+        this.numElementValuePairsOffset = annotation.length == 0 ? -1 : annotation.length - 2;
+        this.previousAnnotation = previousAnnotation;
+        if (previousAnnotation != null) {
+            previousAnnotation.nextAnnotation = this;
+        }
+    }
 
     /**
-     * Previous annotation writer. This field is used to store annotation lists.
-     */
-    AnnotationWriter prev;
-
-    // ------------------------------------------------------------------------
-    // Constructor
-    // ------------------------------------------------------------------------
-
-    /**
-     * Constructs a new {@link AnnotationWriter}.
-     *
-     * @param cw
-     *            the class writer to which this annotation must be added.
-     * @param named
-     *            <tt>true<tt> if values are named, <tt>false</tt> otherwise.
-     * @param bv
-     *            where the annotation values must be stored.
-     * @param parent
-     *            where the number of annotation values must be stored.
-     * @param offset
-     *            where in <tt>parent</tt> the number of annotation values must
-     *            be stored.
-     */
-    AnnotationWriter(final ClassWriter cw, final boolean named,
-            final ByteVector bv, final ByteVector parent, final int offset) {
-        super(Opcodes.ASM6);
-        this.cw = cw;
-        this.named = named;
-        this.bv = bv;
-        this.parent = parent;
-        this.offset = offset;
+      * Constructs a new {@link AnnotationWriter} using named values.
+      *
+      * @param symbolTable where the constants used in this AnnotationWriter must be stored.
+      * @param annotation where the 'annotation' or 'type_annotation' JVMS structure corresponding to
+      *     the visited content must be stored. This ByteVector must already contain all the fields of
+      *     the structure except the last one (the element_value_pairs array).
+      * @param previousAnnotation the previously visited annotation of the
+      *     Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in
+      *     other cases (e.g. nested or array annotations).
+      */
+    AnnotationWriter(
+            final SymbolTable symbolTable,
+            final ByteVector annotation,
+            final AnnotationWriter previousAnnotation) {
+        this(symbolTable, /* useNamedValues = */ true, annotation, previousAnnotation);
     }
 
-    // ------------------------------------------------------------------------
+    // -----------------------------------------------------------------------------------------------
     // Implementation of the AnnotationVisitor abstract class
-    // ------------------------------------------------------------------------
+    // -----------------------------------------------------------------------------------------------
 
     @Override
     public void visit(final String name, final Object value) {
-        ++size;
-        if (named) {
-            bv.putShort(cw.newUTF8(name));
+        // Case of an element_value with a const_value_index, class_info_index or array_index field.
+        // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1.
+        ++numElementValuePairs;
+        if (useNamedValues) {
+            annotation.putShort(symbolTable.addConstantUtf8(name));
         }
         if (value instanceof String) {
-            bv.put12('s', cw.newUTF8((String) value));
+            annotation.put12('s', symbolTable.addConstantUtf8((String) value));
         } else if (value instanceof Byte) {
-            bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
+            annotation.put12('B', symbolTable.addConstantInteger(((Byte) value).byteValue()).index);
         } else if (value instanceof Boolean) {
-            int v = ((Boolean) value).booleanValue() ? 1 : 0;
-            bv.put12('Z', cw.newInteger(v).index);
+            int booleanValue = ((Boolean) value).booleanValue() ? 1 : 0;
+            annotation.put12('Z', symbolTable.addConstantInteger(booleanValue).index);
         } else if (value instanceof Character) {
-            bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
+            annotation.put12('C', symbolTable.addConstantInteger(((Character) value).charValue()).index);
         } else if (value instanceof Short) {
-            bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
+            annotation.put12('S', symbolTable.addConstantInteger(((Short) value).shortValue()).index);
         } else if (value instanceof Type) {
-            bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
+            annotation.put12('c', symbolTable.addConstantUtf8(((Type) value).getDescriptor()));
         } else if (value instanceof byte[]) {
-            byte[] v = (byte[]) value;
-            bv.put12('[', v.length);
-            for (int i = 0; i < v.length; i++) {
-                bv.put12('B', cw.newInteger(v[i]).index);
+            byte[] byteArray = (byte[]) value;
+            annotation.put12('[', byteArray.length);
+            for (byte byteValue : byteArray) {
+                annotation.put12('B', symbolTable.addConstantInteger(byteValue).index);
             }
         } else if (value instanceof boolean[]) {
-            boolean[] v = (boolean[]) value;
-            bv.put12('[', v.length);
-            for (int i = 0; i < v.length; i++) {
-                bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
+            boolean[] booleanArray = (boolean[]) value;
+            annotation.put12('[', booleanArray.length);
+            for (boolean booleanValue : booleanArray) {
+                annotation.put12('Z', symbolTable.addConstantInteger(booleanValue ? 1 : 0).index);
             }
         } else if (value instanceof short[]) {
-            short[] v = (short[]) value;
-            bv.put12('[', v.length);
-            for (int i = 0; i < v.length; i++) {
-                bv.put12('S', cw.newInteger(v[i]).index);
+            short[] shortArray = (short[]) value;
+            annotation.put12('[', shortArray.length);
+            for (short shortValue : shortArray) {
+                annotation.put12('S', symbolTable.addConstantInteger(shortValue).index);
             }
         } else if (value instanceof char[]) {
-            char[] v = (char[]) value;
-            bv.put12('[', v.length);
-            for (int i = 0; i < v.length; i++) {
-                bv.put12('C', cw.newInteger(v[i]).index);
+            char[] charArray = (char[]) value;
+            annotation.put12('[', charArray.length);
+            for (char charValue : charArray) {
+                annotation.put12('C', symbolTable.addConstantInteger(charValue).index);
             }
         } else if (value instanceof int[]) {
-            int[] v = (int[]) value;
-            bv.put12('[', v.length);
-            for (int i = 0; i < v.length; i++) {
-                bv.put12('I', cw.newInteger(v[i]).index);
+            int[] intArray = (int[]) value;
+            annotation.put12('[', intArray.length);
+            for (int intValue : intArray) {
+                annotation.put12('I', symbolTable.addConstantInteger(intValue).index);
             }
         } else if (value instanceof long[]) {
-            long[] v = (long[]) value;
-            bv.put12('[', v.length);
-            for (int i = 0; i < v.length; i++) {
-                bv.put12('J', cw.newLong(v[i]).index);
+            long[] longArray = (long[]) value;
+            annotation.put12('[', longArray.length);
+            for (long longValue : longArray) {
+                annotation.put12('J', symbolTable.addConstantLong(longValue).index);
             }
         } else if (value instanceof float[]) {
-            float[] v = (float[]) value;
-            bv.put12('[', v.length);
-            for (int i = 0; i < v.length; i++) {
-                bv.put12('F', cw.newFloat(v[i]).index);
+            float[] floatArray = (float[]) value;
+            annotation.put12('[', floatArray.length);
+            for (float floatValue : floatArray) {
+                annotation.put12('F', symbolTable.addConstantFloat(floatValue).index);
             }
         } else if (value instanceof double[]) {
-            double[] v = (double[]) value;
-            bv.put12('[', v.length);
-            for (int i = 0; i < v.length; i++) {
-                bv.put12('D', cw.newDouble(v[i]).index);
+            double[] doubleArray = (double[]) value;
+            annotation.put12('[', doubleArray.length);
+            for (double doubleValue : doubleArray) {
+                annotation.put12('D', symbolTable.addConstantDouble(doubleValue).index);
             }
         } else {
-            Item i = cw.newConstItem(value);
-            bv.put12(".s.IFJDCS".charAt(i.type), i.index);
+            Symbol symbol = symbolTable.addConstant(value);
+            annotation.put12(".s.IFJDCS".charAt(symbol.tag), symbol.index);
         }
     }
 
     @Override
-    public void visitEnum(final String name, final String desc,
-            final String value) {
-        ++size;
-        if (named) {
-            bv.putShort(cw.newUTF8(name));
+    public void visitEnum(final String name, final String descriptor, final String value) {
+        // Case of an element_value with an enum_const_value field.
+        // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1.
+        ++numElementValuePairs;
+        if (useNamedValues) {
+            annotation.putShort(symbolTable.addConstantUtf8(name));
         }
-        bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
+        annotation
+                .put12('e', symbolTable.addConstantUtf8(descriptor))
+                .putShort(symbolTable.addConstantUtf8(value));
     }
 
     @Override
-    public AnnotationVisitor visitAnnotation(final String name,
-            final String desc) {
-        ++size;
-        if (named) {
-            bv.putShort(cw.newUTF8(name));
+    public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
+        // Case of an element_value with an annotation_value field.
+        // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1.
+        ++numElementValuePairs;
+        if (useNamedValues) {
+            annotation.putShort(symbolTable.addConstantUtf8(name));
         }
-        // write tag and type, and reserve space for values count
-        bv.put12('@', cw.newUTF8(desc)).putShort(0);
-        return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
+        // Write tag and type_index, and reserve 2 bytes for num_element_value_pairs.
+        annotation.put12('@', symbolTable.addConstantUtf8(descriptor)).putShort(0);
+        return new AnnotationWriter(symbolTable, annotation, null);
     }
 
     @Override
     public AnnotationVisitor visitArray(final String name) {
-        ++size;
-        if (named) {
-            bv.putShort(cw.newUTF8(name));
+        // Case of an element_value with an array_value field.
+        // https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1
+        ++numElementValuePairs;
+        if (useNamedValues) {
+            annotation.putShort(symbolTable.addConstantUtf8(name));
         }
-        // write tag, and reserve space for array size
-        bv.put12('[', 0);
-        return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
+        // Write tag, and reserve 2 bytes for num_values. Here we take advantage of the fact that the
+        // end of an element_value of array type is similar to the end of an 'annotation' structure: an
+        // unsigned short num_values followed by num_values element_value, versus an unsigned short
+        // num_element_value_pairs, followed by num_element_value_pairs { element_name_index,
+        // element_value } tuples. This allows us to use an AnnotationWriter with unnamed values to
+        // visit the array elements. Its num_element_value_pairs will correspond to the number of array
+        // elements and will be stored in what is in fact num_values.
+        annotation.put12('[', 0);
+        return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, annotation, null);
     }
 
     @Override
     public void visitEnd() {
-        if (parent != null) {
-            byte[] data = parent.data;
-            data[offset] = (byte) (size >>> 8);
-            data[offset + 1] = (byte) size;
+        if (numElementValuePairsOffset != -1) {
+            byte[] data = annotation.data;
+            data[numElementValuePairsOffset] = (byte) (numElementValuePairs >>> 8);
+            data[numElementValuePairsOffset + 1] = (byte) numElementValuePairs;
         }
     }
 
-    // ------------------------------------------------------------------------
+    // -----------------------------------------------------------------------------------------------
     // Utility methods
-    // ------------------------------------------------------------------------
+    // -----------------------------------------------------------------------------------------------
 
     /**
-     * Returns the size of this annotation writer list.
-     *
-     * @return the size of this annotation writer list.
-     */
-    int getSize() {
-        int size = 0;
-        AnnotationWriter aw = this;
-        while (aw != null) {
-            size += aw.bv.length;
-            aw = aw.next;
+      * Returns the size of a Runtime[In]Visible[Type]Annotations attribute containing this annotation
+      * and all its <i>predecessors</i> (see {@link #previousAnnotation}. Also adds the attribute name
+      * to the constant pool of the class (if not null).
+      *
+      * @param attributeName one of "Runtime[In]Visible[Type]Annotations", or null.
+      * @return the size in bytes of a Runtime[In]Visible[Type]Annotations attribute containing this
+      *     annotation and all its predecessors. This includes the size of the attribute_name_index and
+      *     attribute_length fields.
+      */
+    int computeAnnotationsSize(final String attributeName) {
+        if (attributeName != null) {
+            symbolTable.addConstantUtf8(attributeName);
         }
-        return size;
+        // The attribute_name_index, attribute_length and num_annotations fields use 8 bytes.
+        int attributeSize = 8;
+        AnnotationWriter annotationWriter = this;
+        while (annotationWriter != null) {
+            attributeSize += annotationWriter.annotation.length;
+            annotationWriter = annotationWriter.previousAnnotation;
+        }
+        return attributeSize;
     }
 
     /**
-     * Puts the annotations of this annotation writer list into the given byte
-     * vector.
-     *
-     * @param out
-     *            where the annotations must be put.
-     */
-    void put(final ByteVector out) {
-        int n = 0;
-        int size = 2;
-        AnnotationWriter aw = this;
-        AnnotationWriter last = null;
-        while (aw != null) {
-            ++n;
-            size += aw.bv.length;
-            aw.visitEnd(); // in case user forgot to call visitEnd
-            aw.prev = last;
-            last = aw;
-            aw = aw.next;
+      * Puts a Runtime[In]Visible[Type]Annotations attribute containing this annotations and all its
+      * <i>predecessors</i> (see {@link #previousAnnotation} in the given ByteVector. Annotations are
+      * put in the same order they have been visited.
+      *
+      * @param attributeNameIndex the constant pool index of the attribute name (one of
+      *     "Runtime[In]Visible[Type]Annotations").
+      * @param output where the attribute must be put.
+      */
+    void putAnnotations(final int attributeNameIndex, final ByteVector output) {
+        int attributeLength = 2; // For num_annotations.
+        int numAnnotations = 0;
+        AnnotationWriter annotationWriter = this;
+        AnnotationWriter firstAnnotation = null;
+        while (annotationWriter != null) {
+            // In case the user forgot to call visitEnd().
+            annotationWriter.visitEnd();
+            attributeLength += annotationWriter.annotation.length;
+            numAnnotations++;
+            firstAnnotation = annotationWriter;
+            annotationWriter = annotationWriter.previousAnnotation;
         }
-        out.putInt(size);
-        out.putShort(n);
-        aw = last;
-        while (aw != null) {
-            out.putByteArray(aw.bv.data, 0, aw.bv.length);
-            aw = aw.prev;
+        output.putShort(attributeNameIndex);
+        output.putInt(attributeLength);
+        output.putShort(numAnnotations);
+        annotationWriter = firstAnnotation;
+        while (annotationWriter != null) {
+            output.putByteArray(annotationWriter.annotation.data, 0, annotationWriter.annotation.length);
+            annotationWriter = annotationWriter.nextAnnotation;
         }
     }
 
     /**
-     * Puts the given annotation lists into the given byte vector.
-     *
-     * @param panns
-     *            an array of annotation writer lists.
-     * @param off
-     *            index of the first annotation to be written.
-     * @param out
-     *            where the annotations must be put.
-     */
-    static void put(final AnnotationWriter[] panns, final int off,
-            final ByteVector out) {
-        int size = 1 + 2 * (panns.length - off);
-        for (int i = off; i < panns.length; ++i) {
-            size += panns[i] == null ? 0 : panns[i].getSize();
+      * Returns the size of a Runtime[In]VisibleParameterAnnotations attribute containing all the
+      * annotation lists from the given AnnotationWriter sub-array. Also adds the attribute name to the
+      * constant pool of the class.
+      *
+      * @param attributeName one of "Runtime[In]VisibleParameterAnnotations".
+      * @param annotationWriters an array of AnnotationWriter lists (designated by their <i>last</i>
+      *     element).
+      * @param annotableParameterCount the number of elements in annotationWriters to take into account
+      *     (elements [0..annotableParameterCount[ are taken into account).
+      * @return the size in bytes of a Runtime[In]VisibleParameterAnnotations attribute corresponding
+      *     to the given sub-array of AnnotationWriter lists. This includes the size of the
+      *     attribute_name_index and attribute_length fields.
+      */
+    static int computeParameterAnnotationsSize(
+            final String attributeName,
+            final AnnotationWriter[] annotationWriters,
+            final int annotableParameterCount) {
+        // Note: attributeName is added to the constant pool by the call to computeAnnotationsSize
+        // below. This assumes that there is at least one non-null element in the annotationWriters
+        // sub-array (which is ensured by the lazy instantiation of this array in MethodWriter).
+        // The attribute_name_index, attribute_length and num_parameters fields use 7 bytes, and each
+        // element of the parameter_annotations array uses 2 bytes for its num_annotations field.
+        int attributeSize = 7 + 2 * annotableParameterCount;
+        for (int i = 0; i < annotableParameterCount; ++i) {
+            AnnotationWriter annotationWriter = annotationWriters[i];
+            attributeSize +=
+                    annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(attributeName) - 8;
         }
-        out.putInt(size).putByte(panns.length - off);
-        for (int i = off; i < panns.length; ++i) {
-            AnnotationWriter aw = panns[i];
-            AnnotationWriter last = null;
-            int n = 0;
-            while (aw != null) {
-                ++n;
-                aw.visitEnd(); // in case user forgot to call visitEnd
-                aw.prev = last;
-                last = aw;
-                aw = aw.next;
+        return attributeSize;
+    }
+
+    /**
+      * Puts a Runtime[In]VisibleParameterAnnotations attribute containing all the annotation lists
+      * from the given AnnotationWriter sub-array in the given ByteVector.
+      *
+      * @param attributeNameIndex constant pool index of the attribute name (one of
+      *     Runtime[In]VisibleParameterAnnotations).
+      * @param annotationWriters an array of AnnotationWriter lists (designated by their <i>last</i>
+      *     element).
+      * @param annotableParameterCount the number of elements in annotationWriters to put (elements
+      *     [0..annotableParameterCount[ are put).
+      * @param output where the attribute must be put.
+      */
+    static void putParameterAnnotations(
+            final int attributeNameIndex,
+            final AnnotationWriter[] annotationWriters,
+            final int annotableParameterCount,
+            final ByteVector output) {
+        // The num_parameters field uses 1 byte, and each element of the parameter_annotations array
+        // uses 2 bytes for its num_annotations field.
+        int attributeLength = 1 + 2 * annotableParameterCount;
+        for (int i = 0; i < annotableParameterCount; ++i) {
+            AnnotationWriter annotationWriter = annotationWriters[i];
+            attributeLength +=
+                    annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(null) - 8;
+        }
+        output.putShort(attributeNameIndex);
+        output.putInt(attributeLength);
+        output.putByte(annotableParameterCount);
+        for (int i = 0; i < annotableParameterCount; ++i) {
+            AnnotationWriter annotationWriter = annotationWriters[i];
+            AnnotationWriter firstAnnotation = null;
+            int numAnnotations = 0;
+            while (annotationWriter != null) {
+                // In case user the forgot to call visitEnd().
+                annotationWriter.visitEnd();
+                numAnnotations++;
+                firstAnnotation = annotationWriter;
+                annotationWriter = annotationWriter.previousAnnotation;
             }
-            out.putShort(n);
-            aw = last;
-            while (aw != null) {
-                out.putByteArray(aw.bv.data, 0, aw.bv.length);
-                aw = aw.prev;
+            output.putShort(numAnnotations);
+            annotationWriter = firstAnnotation;
+            while (annotationWriter != null) {
+                output.putByteArray(
+                        annotationWriter.annotation.data, 0, annotationWriter.annotation.length);
+                annotationWriter = annotationWriter.nextAnnotation;
             }
         }
     }
-
-    /**
-     * Puts the given type reference and type path into the given bytevector.
-     * LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported.
-     *
-     * @param typeRef
-     *            a reference to the annotated type. See {@link TypeReference}.
-     * @param typePath
-     *            the path to the annotated type argument, wildcard bound, array
-     *            element type, or static inner type within 'typeRef'. May be
-     *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
-     * @param out
-     *            where the type reference and type path must be put.
-     */
-    static void putTarget(int typeRef, TypePath typePath, ByteVector out) {
-        switch (typeRef >>> 24) {
-        case 0x00: // CLASS_TYPE_PARAMETER
-        case 0x01: // METHOD_TYPE_PARAMETER
-        case 0x16: // METHOD_FORMAL_PARAMETER
-            out.putShort(typeRef >>> 16);
-            break;
-        case 0x13: // FIELD
-        case 0x14: // METHOD_RETURN
-        case 0x15: // METHOD_RECEIVER
-            out.putByte(typeRef >>> 24);
-            break;
-        case 0x47: // CAST
-        case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
-        case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
-        case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
-        case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
-            out.putInt(typeRef);
-            break;
-        // case 0x10: // CLASS_EXTENDS
-        // case 0x11: // CLASS_TYPE_PARAMETER_BOUND
-        // case 0x12: // METHOD_TYPE_PARAMETER_BOUND
-        // case 0x17: // THROWS
-        // case 0x42: // EXCEPTION_PARAMETER
-        // case 0x43: // INSTANCEOF
-        // case 0x44: // NEW
-        // case 0x45: // CONSTRUCTOR_REFERENCE
-        // case 0x46: // METHOD_REFERENCE
-        default:
-            out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8);
-            break;
-        }
-        if (typePath == null) {
-            out.putByte(0);
-        } else {
-            int length = typePath.b[typePath.offset] * 2 + 1;
-            out.putByteArray(typePath.b, typePath.offset, length);
-        }
-    }
 }
--- a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Attribute.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Attribute.java	Wed Nov 14 17:16:44 2018 +0530
@@ -58,297 +58,299 @@
  */
 package jdk.internal.org.objectweb.asm;
 
-import java.util.Arrays;
-
 /**
- * A non standard class, field, method or code attribute.
+ * A non standard class, field, method or code attribute, as defined in the Java Virtual Machine
+ * Specification (JVMS).
  *
+ * @see <a href= "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7">JVMS
+ *     4.7</a>
+ * @see <a href= "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.3">JVMS
+ *     4.7.3</a>
  * @author Eric Bruneton
  * @author Eugene Kuleshov
  */
 public class Attribute {
 
-    /**
-     * The type of this attribute.
-     */
+    /** The type of this attribute, also called its name in the JVMS. */
     public final String type;
 
     /**
-     * The raw value of this attribute, used only for unknown attributes.
-     */
-    byte[] value;
+      * The raw content of this attribute, only used for unknown attributes (see {@link #isUnknown()}).
+      * The 6 header bytes of the attribute (attribute_name_index and attribute_length) are <i>not</i>
+      * included.
+      */
+    private byte[] content;
 
     /**
-     * The next attribute in this attribute list. May be <tt>null</tt>.
-     */
-    Attribute next;
+      * The next attribute in this attribute list (Attribute instances can be linked via this field to
+      * store a list of class, field, method or code attributes). May be {@literal null}.
+      */
+    Attribute nextAttribute;
 
     /**
-     * Constructs a new empty attribute.
-     *
-     * @param type
-     *            the type of the attribute.
-     */
+      * Constructs a new empty attribute.
+      *
+      * @param type the type of the attribute.
+      */
     protected Attribute(final String type) {
         this.type = type;
     }
 
     /**
-     * Returns <tt>true</tt> if this type of attribute is unknown. The default
-     * implementation of this method always returns <tt>true</tt>.
-     *
-     * @return <tt>true</tt> if this type of attribute is unknown.
-     */
+      * Returns {@literal true} if this type of attribute is unknown. This means that the attribute
+      * content can't be parsed to extract constant pool references, labels, etc. Instead, the
+      * attribute content is read as an opaque byte array, and written back as is. This can lead to
+      * invalid attributes, if the content actually contains constant pool references, labels, or other
+      * symbolic references that need to be updated when there are changes to the constant pool, the
+      * method bytecode, etc. The default implementation of this method always returns {@literal true}.
+      *
+      * @return {@literal true} if this type of attribute is unknown.
+      */
     public boolean isUnknown() {
         return true;
     }
 
     /**
-     * Returns <tt>true</tt> if this type of attribute is a code attribute.
-     *
-     * @return <tt>true</tt> if this type of attribute is a code attribute.
-     */
+      * Returns {@literal true} if this type of attribute is a code attribute.
+      *
+      * @return {@literal true} if this type of attribute is a code attribute.
+      */
     public boolean isCodeAttribute() {
         return false;
     }
 
     /**
-     * Returns the labels corresponding to this attribute.
-     *
-     * @return the labels corresponding to this attribute, or <tt>null</tt> if
-     *         this attribute is not a code attribute that contains labels.
-     */
+      * Returns the labels corresponding to this attribute.
+      *
+      * @return the labels corresponding to this attribute, or {@literal null} if this attribute is not
+      *     a code attribute that contains labels.
+      */
     protected Label[] getLabels() {
-        return null;
+        return new Label[0];
     }
 
     /**
-     * Reads a {@link #type type} attribute. This method must return a
-     * <i>new</i> {@link Attribute} object, of type {@link #type type},
-     * corresponding to the <tt>len</tt> bytes starting at the given offset, in
-     * the given class reader.
-     *
-     * @param cr
-     *            the class that contains the attribute to be read.
-     * @param off
-     *            index of the first byte of the attribute's content in
-     *            {@link ClassReader#b cr.b}. The 6 attribute header bytes,
-     *            containing the type and the length of the attribute, are not
-     *            taken into account here.
-     * @param len
-     *            the length of the attribute's content.
-     * @param buf
-     *            buffer to be used to call {@link ClassReader#readUTF8
-     *            readUTF8}, {@link ClassReader#readClass(int,char[]) readClass}
-     *            or {@link ClassReader#readConst readConst}.
-     * @param codeOff
-     *            index of the first byte of code's attribute content in
-     *            {@link ClassReader#b cr.b}, or -1 if the attribute to be read
-     *            is not a code attribute. The 6 attribute header bytes,
-     *            containing the type and the length of the attribute, are not
-     *            taken into account here.
-     * @param labels
-     *            the labels of the method's code, or <tt>null</tt> if the
-     *            attribute to be read is not a code attribute.
-     * @return a <i>new</i> {@link Attribute} object corresponding to the given
-     *         bytes.
-     */
-    protected Attribute read(final ClassReader cr, final int off,
-            final int len, final char[] buf, final int codeOff,
+      * Reads a {@link #type} attribute. This method must return a <i>new</i> {@link Attribute} object,
+      * of type {@link #type}, corresponding to the 'length' bytes starting at 'offset', in the given
+      * ClassReader.
+      *
+      * @param classReader the class that contains the attribute to be read.
+      * @param offset index of the first byte of the attribute's content in {@link ClassReader#b}. The
+      *     6 attribute header bytes (attribute_name_index and attribute_length) are not taken into
+      *     account here.
+      * @param length the length of the attribute's content (excluding the 6 attribute header bytes).
+      * @param charBuffer the buffer to be used to call the ClassReader methods requiring a
+      *     'charBuffer' parameter.
+      * @param codeAttributeOffset index of the first byte of content of the enclosing Code attribute
+      *     in {@link ClassReader#b}, or -1 if the attribute to be read is not a code attribute. The 6
+      *     attribute header bytes (attribute_name_index and attribute_length) are not taken into
+      *     account here.
+      * @param labels the labels of the method's code, or {@literal null} if the attribute to be read
+      *     is not a code attribute.
+      * @return a <i>new</i> {@link Attribute} object corresponding to the specified bytes.
+      */
+    protected Attribute read(
+            final ClassReader classReader,
+            final int offset,
+            final int length,
+            final char[] charBuffer,
+            final int codeAttributeOffset,
             final Label[] labels) {
-        Attribute attr = new Attribute(type);
-        attr.value = new byte[len];
-        System.arraycopy(cr.b, off, attr.value, 0, len);
-        return attr;
+        Attribute attribute = new Attribute(type);
+        attribute.content = new byte[length];
+        System.arraycopy(classReader.b, offset, attribute.content, 0, length);
+        return attribute;
     }
 
     /**
-     * Returns the byte array form of this attribute.
-     *
-     * @param cw
-     *            the class to which this attribute must be added. This
-     *            parameter can be used to add to the constant pool of this
-     *            class the items that corresponds to this attribute.
-     * @param code
-     *            the bytecode of the method corresponding to this code
-     *            attribute, or <tt>null</tt> if this attribute is not a code
-     *            attributes.
-     * @param len
-     *            the length of the bytecode of the method corresponding to this
-     *            code attribute, or <tt>null</tt> if this attribute is not a
-     *            code attribute.
-     * @param maxStack
-     *            the maximum stack size of the method corresponding to this
-     *            code attribute, or -1 if this attribute is not a code
-     *            attribute.
-     * @param maxLocals
-     *            the maximum number of local variables of the method
-     *            corresponding to this code attribute, or -1 if this attribute
-     *            is not a code attribute.
-     * @return the byte array form of this attribute.
-     */
-    protected ByteVector write(final ClassWriter cw, final byte[] code,
-            final int len, final int maxStack, final int maxLocals) {
-        ByteVector v = new ByteVector();
-        v.data = value;
-        v.length = value.length;
-        return v;
+      * Returns the byte array form of the content of this attribute. The 6 header bytes
+      * (attribute_name_index and attribute_length) must <i>not</i> be added in the returned
+      * ByteVector.
+      *
+      * @param classWriter the class to which this attribute must be added. This parameter can be used
+      *     to add the items that corresponds to this attribute to the constant pool of this class.
+      * @param code the bytecode of the method corresponding to this code attribute, or {@literal null}
+      *     if this attribute is not a code attribute. Corresponds to the 'code' field of the Code
+      *     attribute.
+      * @param codeLength the length of the bytecode of the method corresponding to this code
+      *     attribute, or 0 if this attribute is not a code attribute. Corresponds to the 'code_length'
+      *     field of the Code attribute.
+      * @param maxStack the maximum stack size of the method corresponding to this code attribute, or
+      *     -1 if this attribute is not a code attribute.
+      * @param maxLocals the maximum number of local variables of the method corresponding to this code
+      *     attribute, or -1 if this attribute is not a code attribute.
+      * @return the byte array form of this attribute.
+      */
+    protected ByteVector write(
+            final ClassWriter classWriter,
+            final byte[] code,
+            final int codeLength,
+            final int maxStack,
+            final int maxLocals) {
+        return new ByteVector(content);
     }
 
     /**
-     * Returns the length of the attribute list that begins with this attribute.
-     *
-     * @return the length of the attribute list that begins with this attribute.
-     */
-    final int getCount() {
+      * Returns the number of attributes of the attribute list that begins with this attribute.
+      *
+      * @return the number of attributes of the attribute list that begins with this attribute.
+      */
+    final int getAttributeCount() {
         int count = 0;
-        Attribute attr = this;
-        while (attr != null) {
+        Attribute attribute = this;
+        while (attribute != null) {
             count += 1;
-            attr = attr.next;
+            attribute = attribute.nextAttribute;
         }
         return count;
     }
 
     /**
-     * Returns the size of all the attributes in this attribute list.
-     *
-     * @param cw
-     *            the class writer to be used to convert the attributes into
-     *            byte arrays, with the {@link #write write} method.
-     * @param code
-     *            the bytecode of the method corresponding to these code
-     *            attributes, or <tt>null</tt> if these attributes are not code
-     *            attributes.
-     * @param len
-     *            the length of the bytecode of the method corresponding to
-     *            these code attributes, or <tt>null</tt> if these attributes
-     *            are not code attributes.
-     * @param maxStack
-     *            the maximum stack size of the method corresponding to these
-     *            code attributes, or -1 if these attributes are not code
-     *            attributes.
-     * @param maxLocals
-     *            the maximum number of local variables of the method
-     *            corresponding to these code attributes, or -1 if these
-     *            attributes are not code attributes.
-     * @return the size of all the attributes in this attribute list. This size
-     *         includes the size of the attribute headers.
-     */
-    final int getSize(final ClassWriter cw, final byte[] code, final int len,
-            final int maxStack, final int maxLocals) {
-        Attribute attr = this;
+      * Returns the total size in bytes of all the attributes in the attribute list that begins with
+      * this attribute. This size includes the 6 header bytes (attribute_name_index and
+      * attribute_length) per attribute. Also adds the attribute type names to the constant pool.
+      *
+      * @param symbolTable where the constants used in the attributes must be stored.
+      * @return the size of all the attributes in this attribute list. This size includes the size of
+      *     the attribute headers.
+      */
+    final int computeAttributesSize(final SymbolTable symbolTable) {
+        final byte[] code = null;
+        final int codeLength = 0;
+        final int maxStack = -1;
+        final int maxLocals = -1;
+        return computeAttributesSize(symbolTable, code, codeLength, maxStack, maxLocals);
+    }
+
+    /**
+      * Returns the total size in bytes of all the attributes in the attribute list that begins with
+      * this attribute. This size includes the 6 header bytes (attribute_name_index and
+      * attribute_length) per attribute. Also adds the attribute type names to the constant pool.
+      *
+      * @param symbolTable where the constants used in the attributes must be stored.
+      * @param code the bytecode of the method corresponding to these code attributes, or {@literal
+      *     null} if they are not code attributes. Corresponds to the 'code' field of the Code
+      *     attribute.
+      * @param codeLength the length of the bytecode of the method corresponding to these code
+      *     attributes, or 0 if they are not code attributes. Corresponds to the 'code_length' field of
+      *     the Code attribute.
+      * @param maxStack the maximum stack size of the method corresponding to these code attributes, or
+      *     -1 if they are not code attributes.
+      * @param maxLocals the maximum number of local variables of the method corresponding to these
+      *     code attributes, or -1 if they are not code attribute.
+      * @return the size of all the attributes in this attribute list. This size includes the size of
+      *     the attribute headers.
+      */
+    final int computeAttributesSize(
+            final SymbolTable symbolTable,
+            final byte[] code,
+            final int codeLength,
+            final int maxStack,
+            final int maxLocals) {
+        final ClassWriter classWriter = symbolTable.classWriter;
         int size = 0;
-        while (attr != null) {
-            cw.newUTF8(attr.type);
-            size += attr.write(cw, code, len, maxStack, maxLocals).length + 6;
-            attr = attr.next;
+        Attribute attribute = this;
+        while (attribute != null) {
+            symbolTable.addConstantUtf8(attribute.type);
+            size += 6 + attribute.write(classWriter, code, codeLength, maxStack, maxLocals).length;
+            attribute = attribute.nextAttribute;
         }
         return size;
     }
 
     /**
-     * Writes all the attributes of this attribute list in the given byte
-     * vector.
-     *
-     * @param cw
-     *            the class writer to be used to convert the attributes into
-     *            byte arrays, with the {@link #write write} method.
-     * @param code
-     *            the bytecode of the method corresponding to these code
-     *            attributes, or <tt>null</tt> if these attributes are not code
-     *            attributes.
-     * @param len
-     *            the length of the bytecode of the method corresponding to
-     *            these code attributes, or <tt>null</tt> if these attributes
-     *            are not code attributes.
-     * @param maxStack
-     *            the maximum stack size of the method corresponding to these
-     *            code attributes, or -1 if these attributes are not code
-     *            attributes.
-     * @param maxLocals
-     *            the maximum number of local variables of the method
-     *            corresponding to these code attributes, or -1 if these
-     *            attributes are not code attributes.
-     * @param out
-     *            where the attributes must be written.
-     */
-    final void put(final ClassWriter cw, final byte[] code, final int len,
-            final int maxStack, final int maxLocals, final ByteVector out) {
-        Attribute attr = this;
-        while (attr != null) {
-            ByteVector b = attr.write(cw, code, len, maxStack, maxLocals);
-            out.putShort(cw.newUTF8(attr.type)).putInt(b.length);
-            out.putByteArray(b.data, 0, b.length);
-            attr = attr.next;
+      * Puts all the attributes of the attribute list that begins with this attribute, in the given
+      * byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per
+      * attribute.
+      *
+      * @param symbolTable where the constants used in the attributes must be stored.
+      * @param output where the attributes must be written.
+      */
+    final void putAttributes(final SymbolTable symbolTable, final ByteVector output) {
+        final byte[] code = null;
+        final int codeLength = 0;
+        final int maxStack = -1;
+        final int maxLocals = -1;
+        putAttributes(symbolTable, code, codeLength, maxStack, maxLocals, output);
+    }
+
+    /**
+      * Puts all the attributes of the attribute list that begins with this attribute, in the given
+      * byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per
+      * attribute.
+      *
+      * @param symbolTable where the constants used in the attributes must be stored.
+      * @param code the bytecode of the method corresponding to these code attributes, or {@literal
+      *     null} if they are not code attributes. Corresponds to the 'code' field of the Code
+      *     attribute.
+      * @param codeLength the length of the bytecode of the method corresponding to these code
+      *     attributes, or 0 if they are not code attributes. Corresponds to the 'code_length' field of
+      *     the Code attribute.
+      * @param maxStack the maximum stack size of the method corresponding to these code attributes, or
+      *     -1 if they are not code attributes.
+      * @param maxLocals the maximum number of local variables of the method corresponding to these
+      *     code attributes, or -1 if they are not code attribute.
+      * @param output where the attributes must be written.
+      */
+    final void putAttributes(
+            final SymbolTable symbolTable,
+            final byte[] code,
+            final int codeLength,
+            final int maxStack,
+            final int maxLocals,
+            final ByteVector output) {
+        final ClassWriter classWriter = symbolTable.classWriter;
+        Attribute attribute = this;
+        while (attribute != null) {
+            ByteVector attributeContent =
+                    attribute.write(classWriter, code, codeLength, maxStack, maxLocals);
+            // Put attribute_name_index and attribute_length.
+            output.putShort(symbolTable.addConstantUtf8(attribute.type)).putInt(attributeContent.length);
+            output.putByteArray(attributeContent.data, 0, attributeContent.length);
+            attribute = attribute.nextAttribute;
         }
     }
 
-    //The stuff below is temporary - once proper support for nestmate attribute has been added, it can be safely removed.
-    //see also changes in ClassReader.accept.
+    /** A set of attribute prototypes (attributes with the same type are considered equal). */
+    static final class Set {
 
-    public static class NestMembers extends Attribute {
-        public NestMembers() {
-            super("NestMembers");
+        private static final int SIZE_INCREMENT = 6;
+
+        private int size;
+        private Attribute[] data = new Attribute[SIZE_INCREMENT];
+
+        void addAttributes(final Attribute attributeList) {
+            Attribute attribute = attributeList;
+            while (attribute != null) {
+                if (!contains(attribute)) {
+                    add(attribute);
+                }
+                attribute = attribute.nextAttribute;
+            }
         }
 
-        byte[] bytes;
-        String[] classes;
-
-        @Override
-        protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
-            int offset = off;
-            NestMembers a = new NestMembers();
-            int size = cr.readShort(off);
-            a.classes = new String[size];
-            off += 2;
-            for (int i = 0; i < size ; i++) {
-                a.classes[i] = cr.readClass(off, buf);
-                off += 2;
-            }
-            a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
-            return a;
+        Attribute[] toArray() {
+            Attribute[] result = new Attribute[size];
+            System.arraycopy(data, 0, result, 0, size);
+            return result;
         }
 
-        @Override
-        protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
-            ByteVector v = new ByteVector(bytes.length);
-            v.putShort(classes.length);
-            for (String s : classes) {
-                v.putShort(cw.newClass(s));
+        private boolean contains(final Attribute attribute) {
+            for (int i = 0; i < size; ++i) {
+                if (data[i].type.equals(attribute.type)) {
+                    return true;
+                }
             }
-            return v;
+            return false;
+        }
+
+        private void add(final Attribute attribute) {
+            if (size >= data.length) {
+                Attribute[] newData = new Attribute[data.length + SIZE_INCREMENT];
+                System.arraycopy(data, 0, newData, 0, size);
+                data = newData;
+            }
+            data[size++] = attribute;
         }
     }
-
-    public static class NestHost extends Attribute {
-
-        byte[] bytes;
-        String clazz;
-
-        public NestHost() {
-            super("NestHost");
-        }
-
-        @Override
-        protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
-            int offset = off;
-            NestHost a = new NestHost();
-            a.clazz = cr.readClass(off, buf);
-            a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
-            return a;
-        }
-
-        @Override
-        protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
-            ByteVector v = new ByteVector(bytes.length);
-            v.putShort(cw.newClass(clazz));
-            return v;
-        }
-    }
-
-    static final Attribute[] DEFAULT_ATTRIBUTE_PROTOS = new Attribute[] {
-        new NestMembers(),
-        new NestHost()
-    };
 }
--- a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ByteVector.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ByteVector.java	Wed Nov 14 17:16:44 2018 +0530
@@ -59,309 +59,333 @@
 package jdk.internal.org.objectweb.asm;
 
 /**
- * A dynamically extensible vector of bytes. This class is roughly equivalent to
- * a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient.
+ * A dynamically extensible vector of bytes. This class is roughly equivalent to a DataOutputStream
+ * on top of a ByteArrayOutputStream, but is more efficient.
  *
  * @author Eric Bruneton
  */
 public class ByteVector {
 
-    /**
-     * The content of this vector.
-     */
+    /** The content of this vector. Only the first {@link #length} bytes contain real data. */
     byte[] data;
 
-    /**
-     * Actual number of bytes in this vector.
-     */
+    /** The actual number of bytes in this vector. */
     int length;
 
-    /**
-     * Constructs a new {@link ByteVector ByteVector} with a default initial
-     * size.
-     */
+    /** Constructs a new {@link ByteVector} with a default initial capacity. */
     public ByteVector() {
         data = new byte[64];
     }
 
     /**
-     * Constructs a new {@link ByteVector ByteVector} with the given initial
-     * size.
-     *
-     * @param initialSize
-     *            the initial size of the byte vector to be constructed.
-     */
-    public ByteVector(final int initialSize) {
-        data = new byte[initialSize];
+      * Constructs a new {@link ByteVector} with the given initial capacity.
+      *
+      * @param initialCapacity the initial capacity of the byte vector to be constructed.
+      */
+    public ByteVector(final int initialCapacity) {
+        data = new byte[initialCapacity];
     }
 
     /**
-     * Puts a byte into this byte vector. The byte vector is automatically
-     * enlarged if necessary.
-     *
-     * @param b
-     *            a byte.
-     * @return this byte vector.
-     */
-    public ByteVector putByte(final int b) {
-        int length = this.length;
-        if (length + 1 > data.length) {
+      * Constructs a new {@link ByteVector} from the given initial data.
+      *
+      * @param data the initial data of the new byte vector.
+      */
+    ByteVector(final byte[] data) {
+        this.data = data;
+        this.length = data.length;
+    }
+
+    /**
+      * Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary.
+      *
+      * @param byteValue a byte.
+      * @return this byte vector.
+      */
+    public ByteVector putByte(final int byteValue) {
+        int currentLength = length;
+        if (currentLength + 1 > data.length) {
             enlarge(1);
         }
-        data[length++] = (byte) b;
-        this.length = length;
+        data[currentLength++] = (byte) byteValue;
+        length = currentLength;
         return this;
     }
 
     /**
-     * Puts two bytes into this byte vector. The byte vector is automatically
-     * enlarged if necessary.
-     *
-     * @param b1
-     *            a byte.
-     * @param b2
-     *            another byte.
-     * @return this byte vector.
-     */
-    ByteVector put11(final int b1, final int b2) {
-        int length = this.length;
-        if (length + 2 > data.length) {
+      * Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary.
+      *
+      * @param byteValue1 a byte.
+      * @param byteValue2 another byte.
+      * @return this byte vector.
+      */
+    final ByteVector put11(final int byteValue1, final int byteValue2) {
+        int currentLength = length;
+        if (currentLength + 2 > data.length) {
             enlarge(2);
         }
-        byte[] data = this.data;
-        data[length++] = (byte) b1;
-        data[length++] = (byte) b2;
-        this.length = length;
+        byte[] currentData = data;
+        currentData[currentLength++] = (byte) byteValue1;
+        currentData[currentLength++] = (byte) byteValue2;
+        length = currentLength;
         return this;
     }
 
     /**
-     * Puts a short into this byte vector. The byte vector is automatically
-     * enlarged if necessary.
-     *
-     * @param s
-     *            a short.
-     * @return this byte vector.
-     */
-    public ByteVector putShort(final int s) {
-        int length = this.length;
-        if (length + 2 > data.length) {
+      * Puts a short into this byte vector. The byte vector is automatically enlarged if necessary.
+      *
+      * @param shortValue a short.
+      * @return this byte vector.
+      */
+    public ByteVector putShort(final int shortValue) {
+        int currentLength = length;
+        if (currentLength + 2 > data.length) {
             enlarge(2);
         }
-        byte[] data = this.data;
-        data[length++] = (byte) (s >>> 8);
-        data[length++] = (byte) s;
-        this.length = length;
+        byte[] currentData = data;
+        currentData[currentLength++] = (byte) (shortValue >>> 8);
+        currentData[currentLength++] = (byte) shortValue;
+        length = currentLength;
         return this;
     }
 
     /**
-     * Puts a byte and a short into this byte vector. The byte vector is
-     * automatically enlarged if necessary.
-     *
-     * @param b
-     *            a byte.
-     * @param s
-     *            a short.
-     * @return this byte vector.
-     */
-    ByteVector put12(final int b, final int s) {
-        int length = this.length;
-        if (length + 3 > data.length) {
+      * Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if
+      * necessary.
+      *
+      * @param byteValue a byte.
+      * @param shortValue a short.
+      * @return this byte vector.
+      */
+    final ByteVector put12(final int byteValue, final int shortValue) {
+        int currentLength = length;
+        if (currentLength + 3 > data.length) {
             enlarge(3);
         }
-        byte[] data = this.data;
-        data[length++] = (byte) b;
-        data[length++] = (byte) (s >>> 8);
-        data[length++] = (byte) s;
-        this.length = length;
+        byte[] currentData = data;
+        currentData[currentLength++] = (byte) byteValue;
+        currentData[currentLength++] = (byte) (shortValue >>> 8);
+        currentData[currentLength++] = (byte) shortValue;
+        length = currentLength;
         return this;
     }
 
     /**
-     * Puts an int into this byte vector. The byte vector is automatically
-     * enlarged if necessary.
-     *
-     * @param i
-     *            an int.
-     * @return this byte vector.
-     */
-    public ByteVector putInt(final int i) {
-        int length = this.length;
-        if (length + 4 > data.length) {
+      * Puts two bytes and a short into this byte vector. The byte vector is automatically enlarged if
+      * necessary.
+      *
+      * @param byteValue1 a byte.
+      * @param byteValue2 another byte.
+      * @param shortValue a short.
+      * @return this byte vector.
+      */
+    final ByteVector put112(final int byteValue1, final int byteValue2, final int shortValue) {
+        int currentLength = length;
+        if (currentLength + 4 > data.length) {
             enlarge(4);
         }
-        byte[] data = this.data;
-        data[length++] = (byte) (i >>> 24);
-        data[length++] = (byte) (i >>> 16);
-        data[length++] = (byte) (i >>> 8);
-        data[length++] = (byte) i;
-        this.length = length;
+        byte[] currentData = data;
+        currentData[currentLength++] = (byte) byteValue1;
+        currentData[currentLength++] = (byte) byteValue2;
+        currentData[currentLength++] = (byte) (shortValue >>> 8);
+        currentData[currentLength++] = (byte) shortValue;
+        length = currentLength;
         return this;
     }
 
     /**
-     * Puts a long into this byte vector. The byte vector is automatically
-     * enlarged if necessary.
-     *
-     * @param l
-     *            a long.
-     * @return this byte vector.
-     */
-    public ByteVector putLong(final long l) {
-        int length = this.length;
-        if (length + 8 > data.length) {
-            enlarge(8);
+      * Puts an int into this byte vector. The byte vector is automatically enlarged if necessary.
+      *
+      * @param intValue an int.
+      * @return this byte vector.
+      */
+    public ByteVector putInt(final int intValue) {
+        int currentLength = length;
+        if (currentLength + 4 > data.length) {
+            enlarge(4);
         }
-        byte[] data = this.data;
-        int i = (int) (l >>> 32);
-        data[length++] = (byte) (i >>> 24);
-        data[length++] = (byte) (i >>> 16);
-        data[length++] = (byte) (i >>> 8);
-        data[length++] = (byte) i;
-        i = (int) l;
-        data[length++] = (byte) (i >>> 24);
-        data[length++] = (byte) (i >>> 16);
-        data[length++] = (byte) (i >>> 8);
-        data[length++] = (byte) i;
-        this.length = length;
+        byte[] currentData = data;
+        currentData[currentLength++] = (byte) (intValue >>> 24);
+        currentData[currentLength++] = (byte) (intValue >>> 16);
+        currentData[currentLength++] = (byte) (intValue >>> 8);
+        currentData[currentLength++] = (byte) intValue;
+        length = currentLength;
         return this;
     }
 
     /**
-     * Puts an UTF8 string into this byte vector. The byte vector is
-     * automatically enlarged if necessary.
-     *
-     * @param s
-     *            a String whose UTF8 encoded length must be less than 65536.
-     * @return this byte vector.
-     */
-    public ByteVector putUTF8(final String s) {
-        int charLength = s.length();
-        if (charLength > 65535) {
-            throw new IllegalArgumentException();
+      * Puts one byte and two shorts into this byte vector. The byte vector is automatically enlarged
+      * if necessary.
+      *
+      * @param byteValue a byte.
+      * @param shortValue1 a short.
+      * @param shortValue2 another short.
+      * @return this byte vector.
+      */
+    final ByteVector put122(final int byteValue, final int shortValue1, final int shortValue2) {
+        int currentLength = length;
+        if (currentLength + 5 > data.length) {
+            enlarge(5);
         }
-        int len = length;
-        if (len + 2 + charLength > data.length) {
-            enlarge(2 + charLength);
-        }
-        byte[] data = this.data;
-        // optimistic algorithm: instead of computing the byte length and then
-        // serializing the string (which requires two loops), we assume the byte
-        // length is equal to char length (which is the most frequent case), and
-        // we start serializing the string right away. During the serialization,
-        // if we find that this assumption is wrong, we continue with the
-        // general method.
-        data[len++] = (byte) (charLength >>> 8);
-        data[len++] = (byte) charLength;
-        for (int i = 0; i < charLength; ++i) {
-            char c = s.charAt(i);
-            if (c >= '\001' && c <= '\177') {
-                data[len++] = (byte) c;
-            } else {
-                length = len;
-                return encodeUTF8(s, i, 65535);
-            }
-        }
-        length = len;
+        byte[] currentData = data;
+        currentData[currentLength++] = (byte) byteValue;
+        currentData[currentLength++] = (byte) (shortValue1 >>> 8);
+        currentData[currentLength++] = (byte) shortValue1;
+        currentData[currentLength++] = (byte) (shortValue2 >>> 8);
+        currentData[currentLength++] = (byte) shortValue2;
+        length = currentLength;
         return this;
     }
 
     /**
-     * Puts an UTF8 string into this byte vector. The byte vector is
-     * automatically enlarged if necessary. The string length is encoded in two
-     * bytes before the encoded characters, if there is space for that (i.e. if
-     * this.length - i - 2 >= 0).
-     *
-     * @param s
-     *            the String to encode.
-     * @param i
-     *            the index of the first character to encode. The previous
-     *            characters are supposed to have already been encoded, using
-     *            only one byte per character.
-     * @param maxByteLength
-     *            the maximum byte length of the encoded string, including the
-     *            already encoded characters.
-     * @return this byte vector.
-     */
-    ByteVector encodeUTF8(final String s, int i, int maxByteLength) {
-        int charLength = s.length();
-        int byteLength = i;
-        char c;
-        for (int j = i; j < charLength; ++j) {
-            c = s.charAt(j);
-            if (c >= '\001' && c <= '\177') {
-                byteLength++;
-            } else if (c > '\u07FF') {
-                byteLength += 3;
-            } else {
-                byteLength += 2;
-            }
+      * Puts a long into this byte vector. The byte vector is automatically enlarged if necessary.
+      *
+      * @param longValue a long.
+      * @return this byte vector.
+      */
+    public ByteVector putLong(final long longValue) {
+        int currentLength = length;
+        if (currentLength + 8 > data.length) {
+            enlarge(8);
         }
-        if (byteLength > maxByteLength) {
-            throw new IllegalArgumentException();
-        }
-        int start = length - i - 2;
-        if (start >= 0) {
-          data[start] = (byte) (byteLength >>> 8);
-          data[start + 1] = (byte) byteLength;
-        }
-        if (length + byteLength - i > data.length) {
-            enlarge(byteLength - i);
-        }
-        int len = length;
-        for (int j = i; j < charLength; ++j) {
-            c = s.charAt(j);
-            if (c >= '\001' && c <= '\177') {
-                data[len++] = (byte) c;
-            } else if (c > '\u07FF') {
-                data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
-                data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
-                data[len++] = (byte) (0x80 | c & 0x3F);
-            } else {
-                data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
-                data[len++] = (byte) (0x80 | c & 0x3F);
-            }
-        }
-        length = len;
+        byte[] currentData = data;
+        int intValue = (int) (longValue >>> 32);
+        currentData[currentLength++] = (byte) (intValue >>> 24);
+        currentData[currentLength++] = (byte) (intValue >>> 16);
+        currentData[currentLength++] = (byte) (intValue >>> 8);
+        currentData[currentLength++] = (byte) intValue;
+        intValue = (int) longValue;
+        currentData[currentLength++] = (byte) (intValue >>> 24);
+        currentData[currentLength++] = (byte) (intValue >>> 16);
+        currentData[currentLength++] = (byte) (intValue >>> 8);
+        currentData[currentLength++] = (byte) intValue;
+        length = currentLength;
         return this;
     }
 
     /**
-     * Puts an array of bytes into this byte vector. The byte vector is
-     * automatically enlarged if necessary.
-     *
-     * @param b
-     *            an array of bytes. May be <tt>null</tt> to put <tt>len</tt>
-     *            null bytes into this byte vector.
-     * @param off
-     *            index of the fist byte of b that must be copied.
-     * @param len
-     *            number of bytes of b that must be copied.
-     * @return this byte vector.
-     */
-    public ByteVector putByteArray(final byte[] b, final int off, final int len) {
-        if (length + len > data.length) {
-            enlarge(len);
+      * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if
+      * necessary.
+      *
+      * @param stringValue a String whose UTF8 encoded length must be less than 65536.
+      * @return this byte vector.
+      */
+    // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
+    public ByteVector putUTF8(final String stringValue) {
+        int charLength = stringValue.length();
+        if (charLength > 65535) {
+            throw new IllegalArgumentException("UTF8 string too large");
         }
-        if (b != null) {
-            System.arraycopy(b, off, data, length, len);
+        int currentLength = length;
+        if (currentLength + 2 + charLength > data.length) {
+            enlarge(2 + charLength);
         }
-        length += len;
+        byte[] currentData = data;
+        // Optimistic algorithm: instead of computing the byte length and then serializing the string
+        // (which requires two loops), we assume the byte length is equal to char length (which is the
+        // most frequent case), and we start serializing the string right away. During the
+        // serialization, if we find that this assumption is wrong, we continue with the general method.
+        currentData[currentLength++] = (byte) (charLength >>> 8);
+        currentData[currentLength++] = (byte) charLength;
+        for (int i = 0; i < charLength; ++i) {
+            char charValue = stringValue.charAt(i);
+            if (charValue >= '\u0001' && charValue <= '\u007F') {
+                currentData[currentLength++] = (byte) charValue;
+            } else {
+                length = currentLength;
+                return encodeUtf8(stringValue, i, 65535);
+            }
+        }
+        length = currentLength;
         return this;
     }
 
     /**
-     * Enlarge this byte vector so that it can receive n more bytes.
-     *
-     * @param size
-     *            number of additional bytes that this byte vector should be
-     *            able to receive.
-     */
+      * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if
+      * necessary. The string length is encoded in two bytes before the encoded characters, if there is
+      * space for that (i.e. if this.length - offset - 2 &gt;= 0).
+      *
+      * @param stringValue the String to encode.
+      * @param offset the index of the first character to encode. The previous characters are supposed
+      *     to have already been encoded, using only one byte per character.
+      * @param maxByteLength the maximum byte length of the encoded string, including the already
+      *     encoded characters.
+      * @return this byte vector.
+      */
+    final ByteVector encodeUtf8(final String stringValue, final int offset, final int maxByteLength) {
+        int charLength = stringValue.length();
+        int byteLength = offset;
+        for (int i = offset; i < charLength; ++i) {
+            char charValue = stringValue.charAt(i);
+            if (charValue >= 0x0001 && charValue <= 0x007F) {
+                byteLength++;
+            } else if (charValue <= 0x07FF) {
+                byteLength += 2;
+            } else {
+                byteLength += 3;
+            }
+        }
+        if (byteLength > maxByteLength) {
+            throw new IllegalArgumentException("UTF8 string too large");
+        }
+        // Compute where 'byteLength' must be stored in 'data', and store it at this location.
+        int byteLengthOffset = length - offset - 2;
+        if (byteLengthOffset >= 0) {
+            data[byteLengthOffset] = (byte) (byteLength >>> 8);
+            data[byteLengthOffset + 1] = (byte) byteLength;
+        }
+        if (length + byteLength - offset > data.length) {
+            enlarge(byteLength - offset);
+        }
+        int currentLength = length;
+        for (int i = offset; i < charLength; ++i) {
+            char charValue = stringValue.charAt(i);
+            if (charValue >= 0x0001 && charValue <= 0x007F) {
+                data[currentLength++] = (byte) charValue;
+            } else if (charValue <= 0x07FF) {
+                data[currentLength++] = (byte) (0xC0 | charValue >> 6 & 0x1F);
+                data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
+            } else {
+                data[currentLength++] = (byte) (0xE0 | charValue >> 12 & 0xF);
+                data[currentLength++] = (byte) (0x80 | charValue >> 6 & 0x3F);
+                data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
+            }
+        }
+        length = currentLength;
+        return this;
+    }
+
+    /**
+      * Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if
+      * necessary.
+      *
+      * @param byteArrayValue an array of bytes. May be {@literal null} to put {@code byteLength} null
+      *     bytes into this byte vector.
+      * @param byteOffset index of the first byte of byteArrayValue that must be copied.
+      * @param byteLength number of bytes of byteArrayValue that must be copied.
+      * @return this byte vector.
+      */
+    public ByteVector putByteArray(
+            final byte[] byteArrayValue, final int byteOffset, final int byteLength) {
+        if (length + byteLength > data.length) {
+            enlarge(byteLength);
+        }
+        if (byteArrayValue != null) {
+            System.arraycopy(byteArrayValue, byteOffset, data, length, byteLength);
+        }
+        length += byteLength;
+        return this;
+    }
+
+    /**
+      * Enlarges this byte vector so that it can receive 'size' more bytes.
+      *
+      * @param size number of additional bytes that this byte vector should be able to receive.
+      */
     private void enlarge(final int size) {
-        int length1 = 2 * data.length;
-        int length2 = length + size;
-        byte[] newData = new byte[length1 > length2 ? length1 : length2];
+        int doubleCapacity = 2 * data.length;
+        int minimalCapacity = length + size;
+        byte[] newData = new byte[doubleCapacity > minimalCapacity ? doubleCapacity : minimalCapacity];
         System.arraycopy(data, 0, newData, 0, length);
         data = newData;
     }
--- a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java	Mon Nov 12 12:39:03 2018 +0530
+++ b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java	Wed Nov 14 17:16:44 2018 +0530
@@ -58,2732 +58,3577 @@
  */
 package jdk.internal.org.objectweb.asm;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 
 /**
- * A Java class parser to make a {@link ClassVisitor} visit an existing class.
- * This class parses a byte array conforming to the Java class file format and
- * calls the appropriate visit methods of a given class visitor for each field,
- * method and bytecode instruction encountered.
+ * A parser to make a {@link ClassVisitor} visit a ClassFile structure, as defined in the Java
+ * Virtual Machine Specification (JVMS). This class parses the ClassFile content and calls the
+ * appropriate visit methods of a given {@link ClassVisitor} for each field, method and bytecode
+ * instruction encountered.
  *
+ * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html">JVMS 4</a>
  * @author Eric Bruneton
  * @author Eugene Kuleshov
  */
 public class ClassReader {
 
     /**
-     * Flag to skip method code. If this class is set <code>CODE</code>
-     * attribute won't be visited. This can be used, for example, to retrieve
-     * annotations for methods and method parameters.
-     */
+      * A flag to skip the Code attributes. If this flag is set the Code attributes are neither parsed
+      * nor visited.
+      */
     public static final int SKIP_CODE = 1;
 
     /**
-     * Flag to skip the debug information in the class. If this flag is set the
-     * debug information of the class is not visited, i.e. the
-     * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and
-     * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be
-     * called.
-     */
+      * A flag to skip the SourceFile, SourceDebugExtension, LocalVariableTable, LocalVariableTypeTable
+      * and LineNumberTable attributes. If this flag is set these attributes are neither parsed nor
+      * visited (i.e. {@link ClassVisitor#visitSource}, {@link MethodVisitor#visitLocalVariable} and
+      * {@link MethodVisitor#visitLineNumber} are not called).
+      */
     public static final int SKIP_DEBUG = 2;
 
     /**
-     * Flag to skip the stack map frames in the class. If this flag is set the
-     * stack map frames of the class is not visited, i.e. the
-     * {@link MethodVisitor#visitFrame visitFrame} method will not be called.
-     * This flag is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is
-     * used: it avoids visiting frames that will be ignored and recomputed from
-     * scratch in the class writer.
-     */
+      * A flag to skip the StackMap and StackMapTable attributes. If this flag is set these attributes
+      * are neither parsed nor visited (i.e. {@link MethodVisitor#visitFrame} is not called). This flag
+      * is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is used: it avoids visiting frames
+      * that will be ignored and recomputed from scratch.
+      */
     public static final int SKIP_FRAMES = 4;
 
     /**
-     * Flag to expand the stack map frames. By default stack map frames are
-     * visited in their original format (i.e. "expanded" for classes whose
-     * version is less than V1_6, and "compressed" for the other classes). If
-     * this flag is set, stack map frames are always visited in expanded format
-     * (this option adds a decompression/recompression step in ClassReader and
-     * ClassWriter which degrades performances quite a lot).
-     */
+      * A flag to expand the stack map frames. By default stack map frames are visited in their
+      * original format (i.e. "expanded" for classes whose version is less than V1_6, and "compressed"
+      * for the other classes). If this flag is set, stack map frames are always visited in expanded
+      * format (this option adds a decompression/compression step in ClassReader and ClassWriter which
+      * degrades performance quite a lot).
+      */
     public static final int EXPAND_FRAMES = 8;
 
     /**
-     * Flag to expand the ASM pseudo instructions into an equivalent sequence of
-     * standard bytecode instructions. When resolving a forward jump it may
-     * happen that the signed 2 bytes offset reserved for it is not sufficient
-     * to store the bytecode offset. In this case the jump instruction is
-     * replaced with a temporary ASM pseudo instruction using an unsigned 2
-     * bytes offset (see Label#resolve). This internal flag is used to re-read
-     * classes containing such instructions, in order to replace them with
-     * standard instructions. In addition, when this flag is used, GOTO_W and
-     * JSR_W are <i>not</i> converted into GOTO and JSR, to make sure that
-     * infinite loops where a GOTO_W is replaced with a GOTO in ClassReader and
-     * converted back to a GOTO_W in ClassWriter cannot occur.
-     */
+      * A flag to expand the ASM specific instructions into an equivalent sequence of standard bytecode
+      * instructions. When resolving a forward jump it may happen that the signed 2 bytes offset
+      * reserved for it is not sufficient to store the bytecode offset. In this case the jump
+      * instruction is replaced with a temporary ASM specific instruction using an unsigned 2 bytes
+      * offset (see {@link Label#resolve}). This internal flag is used to re-read classes containing
+      * such instructions, in order to replace them with standard instructions. In addition, when this
+      * flag is used, goto_w and jsr_w are <i>not</i> converted into goto and jsr, to make sure that
+      * infinite loops where a goto_w is replaced with a goto in ClassReader and converted back to a
+      * goto_w in ClassWriter cannot occur.
+      */
     static final int EXPAND_ASM_INSNS = 256;
 
+    /** The size of the temporary byte array used to read class input streams chunk by chunk. */
+    private static final int INPUT_STREAM_DATA_CHUNK_SIZE = 4096;
+
     /**
-     * The class to be parsed. <i>The content of this array must not be
-     * modified. This field is intended for {@link Attribute} sub classes, and
-     * is normally not needed by class generators or adapters.</i>
-     */
+      * A byte array containing the JVMS ClassFile structure to be parsed. <i>The content of this array
+      * must not be modified. This field is intended for {@link Attribute} sub classes, and is normally
+      * not needed by class visitors.</i>
+      *
+      * <p>NOTE: the ClassFile structure can start at any offset within this array, i.e. it does not
+      * necessarily start at offset 0. Use {@link #getItem} and {@link #header} to get correct
+      * ClassFile element offsets within this byte array.
+      */
+    // DontCheck(MemberName): can't be renamed (for backward binary compatibility).
     public final byte[] b;
 
     /**
-     * The start index of each constant pool item in {@link #b b}, plus one. The
-     * one byte offset skips the constant pool item tag that indicates its type.
-     */
-    private final int[] items;
+      * The offset in bytes, in {@link #b}, of each cp_info entry of the ClassFile's constant_pool
+      * array, <i>plus one</i>. In other words, the offset of constant pool entry i is given by
+      * cpInfoOffsets[i] - 1, i.e. its cp_info's tag field is given by b[cpInfoOffsets[i] - 1].
+      */
+    private final int[] cpInfoOffsets;
 
     /**
-     * The String objects corresponding to the CONSTANT_Utf8 items. This cache
-     * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item,
-     * which GREATLY improves performances (by a factor 2 to 3). This caching
-     * strategy could be extended to all constant pool items, but its benefit
-     * would not be so great for these items (because they are much less
-     * expensive to parse than CONSTANT_Utf8 items).
-     */
-    private final String[] strings;
+      * The String objects corresponding to the CONSTANT_Utf8 constant pool items. This cache avoids
+      * multiple parsing of a given CONSTANT_Utf8 constant pool item.
+      */
+    private final String[] constantUtf8Values;
 
     /**
-     * Maximum length of the strings contained in the constant pool of the
-     * class.
-     */
+      * The ConstantDynamic objects corresponding to the CONSTANT_Dynamic constant pool items. This
+      * cache avoids multiple parsing of a given CONSTANT_Dynamic constant pool item.
+      */
+    private final ConstantDynamic[] constantDynamicValues;
+
+    /**
+      * The start offsets in {@link #b} of each element of the bootstrap_methods array (in the
+      * BootstrapMethods attribute).
+      *
+      * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.23">JVMS
+      *     4.7.23</a>
+      */
+    private final int[] bootstrapMethodOffsets;
+
+    /**
+      * A conservative estimate of the maximum length of the strings contained in the constant pool of
+      * the class.
+      */
     private final int maxStringLength;
 
-    /**
-     * Start index of the class header information (access, name...) in
-     * {@link #b b}.
-     */
+    /** The offset in bytes, in {@link #b}, of the ClassFile's access_flags field. */
     public final int header;
 
-    // ------------------------------------------------------------------------
+    // -----------------------------------------------------------------------------------------------
     // Constructors
-    // ------------------------------------------------------------------------
+    // -----------------------------------------------------------------------------------------------
 
     /**
-     * Constructs a new {@link ClassReader} object.
-     *
-     * @param b
-     *            the bytecode of the class to be read.
-     */
-    public ClassReader(final byte[] b) {
-        this(b, 0, b.length);
+      * Constructs a new {@link ClassReader} object.
+      *
+      * @param classFile the JVMS ClassFile structure to be read.
+      */
+    public ClassReader(final byte[] classFile) {
+        this(classFile, 0, classFile.length);
     }
 
     /**
-     * Constructs a new {@link ClassReader} object.
-     *
-     * @param b
-     *            the bytecode of the class to be read.
-     * @param off
-     *            the start offset of the class data.
-     * @param len
-     *            the length of the class data.
-     */
-    public ClassReader(final byte[] b, final int off, final int len) {
-        this.b = b;
-        // checks the class version
-        if (readShort(off + 6) > Opcodes.V12) {
-            throw new IllegalArgumentException();
-        }
-        // parses the constant pool
-        items = new int[readUnsignedShort(off + 8)];
-        int n = items.length;
-        strings = new String[n];
-        int max = 0;
-        int index = off + 10;
-        for (int i = 1; i < n; ++i) {
-            items[i] = index + 1;
-            int size;
-            switch (b[index]) {
-            case ClassWriter.FIELD:
-            case ClassWriter.METH:
-            case ClassWriter.IMETH:
-            case ClassWriter.INT:
-            case ClassWriter.FLOAT:
-            case ClassWriter.NAME_TYPE:
-            case ClassWriter.INDY:
-            // @@@ ClassWriter.CONDY
-            // Enables MethodHandles.lookup().defineClass to function correctly
-            // when it reads the class name
-            case 17:
-                size = 5;
-                break;
-            case ClassWriter.LONG:
-            case ClassWriter.DOUBLE:
-                size = 9;
-                ++i;
-                break;
-            case ClassWriter.UTF8:
-                size = 3 + readUnsignedShort(index + 1);
-                if (size > max) {
-                    max = size;
-                }
-                break;
-            case ClassWriter.HANDLE:
-                size = 4;
-                break;
-            // case ClassWriter.CLASS:
-            // case ClassWriter.STR:
-            // case ClassWriter.MTYPE
-            // case ClassWriter.PACKAGE:
-            // case ClassWriter.MODULE:
-            default:
-                size = 3;
-                break;
-            }
-            index += size;
-        }
-        maxStringLength = max;
-        // the class header information starts just after the constant pool
-        header = index;
+      * Constructs a new {@link ClassReader} object.
+      *
+      * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read.
+      * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read.
+      * @param classFileLength the length in bytes of the ClassFile to be read.
+      */
+    public ClassReader(
+            final byte[] classFileBuffer,
+            final int classFileOffset,
+            final int classFileLength) { // NOPMD(UnusedFormalParameter) used for backward compatibility.
+        this(classFileBuffer, classFileOffset, /* checkClassVersion = */ true);
     }
 
     /**
-     * Returns the class's access flags (see {@link Opcodes}). This value may
-     * not reflect Deprecated and Synthetic flags when bytecode is before 1.5
-     * and those flags are represented by attributes.
-     *
-     * @return the class access flags
-     *
-     * @see ClassVisitor#visit(int, int, String, String, String, String[])
-     */
+      * Constructs a new {@link ClassReader} object. <i>This internal constructor must not be exposed
+      * as a public API</i>.
+      *
+      * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read.
+      * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read.
+      * @param checkClassVersion whether to check the class version or not.
+      */
+    ClassReader(
+            final byte[] classFileBuffer, final int classFileOffset, final boolean checkClassVersion) {
+        b = classFileBuffer;
+        // Check the class' major_version. This field is after the magic and minor_version fields, which
+        // use 4 and 2 bytes respectively.
+        if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V12) {
+            throw new IllegalArgumentException(
+                    "Unsupported class file major version " + readShort(classFileOffset + 6));
+        }
+        // Create the constant pool arrays. The constant_pool_count field is after the magic,
+        // minor_version and major_version fields, which use 4, 2 and 2 bytes respectively.
+        int constantPoolCount = readUnsignedShort(classFileOffset + 8);
+        cpInfoOffsets = new int[constantPoolCount];
+        constantUtf8Values = new String[constantPoolCount];
+        // Compute the offset of each constant pool entry, as well as a conservative estimate of the
+        // maximum length of the constant pool strings. The first constant pool entry is after the
+        // magic, minor_version, major_version and constant_pool_count fields, which use 4, 2, 2 and 2
+        // bytes respectively.
+        int currentCpInfoIndex = 1;
+        int currentCpInfoOffset = classFileOffset + 10;
+        int currentMaxStringLength = 0;
+        boolean hasConstantDynamic = false;
+        boolean hasConstantInvokeDynamic = false;
+        // The offset of the other entries depend on the total size of all the previous entries.
+        while (currentCpInfoIndex < constantPoolCount) {
+            cpInfoOffsets[currentCpInfoIndex++] = currentCpInfoOffset + 1;
+            int cpInfoSize;
+            switch (classFileBuffer[currentCpInfoOffset]) {
+                case Symbol.CONSTANT_FIELDREF_TAG:
+                case Symbol.CONSTANT_METHODREF_TAG:
+                case Symbol.CONSTANT_INTERFACE_METHODREF_TAG:
+                case Symbol.CONSTANT_INTEGER_TAG:
+                case Symbol.CONSTANT_FLOAT_TAG:
+                case Symbol.CONSTANT_NAME_AND_TYPE_TAG:
+                    cpInfoSize = 5;
+                    break;
+                case Symbol.CONSTANT_DYNAMIC_TAG:
+                    cpInfoSize = 5;
+                    hasConstantDynamic = true;
+                    break;
+                case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG:
+                    cpInfoSize = 5;
+                    hasConstantInvokeDynamic = true;
+                    break;
+                case Symbol.CONSTANT_LONG_TAG:
+                case Symbol.CONSTANT_DOUBLE_TAG:
+                    cpInfoSize = 9;
+                    currentCpInfoIndex++;
+                    break;
+                case Symbol.CONSTANT_UTF8_TAG:
+                    cpInfoSize = 3 + readUnsignedShort(currentCpInfoOffset + 1);
+                    if (cpInfoSize > currentMaxStringLength) {
+                        // The size in bytes of this CONSTANT_Utf8 structure provides a conservative estimate
+                        // of the length in characters of the corresponding string, and is much cheaper to
+                        // compute than this exact length.
+                        currentMaxStringLength = cpInfoSize;
+                    }
+                    break;
+                case Symbol.CONSTANT_METHOD_HANDLE_TAG:
+                    cpInfoSize = 4;
+                    break;
+                case Symbol.CONSTANT_CLASS_TAG:
+                case Symbol.CONSTANT_STRING_TAG:
+                case Symbol.CONSTANT_METHOD_TYPE_TAG:
+                case Symbol.CONSTANT_PACKAGE_TAG:
+                case Symbol.CONSTANT_MODULE_TAG:
+                    cpInfoSize = 3;
+                    break;
+                default:
+                    throw new IllegalArgumentException();
+            }
+            currentCpInfoOffset += cpInfoSize;
+        }
+        maxStringLength = currentMaxStringLength;
+        // The Classfile's access_flags field is just after the last constant pool entry.
+        header = currentCpInfoOffset;
+
+        // Allocate the cache of ConstantDynamic values, if there is at least one.
+        constantDynamicValues = hasConstantDynamic ? new ConstantDynamic[constantPoolCount] : null;
+
+        // Read the BootstrapMethods attribute, if any (only get the offset of each method).
+        bootstrapMethodOffsets =
+                (hasConstantDynamic | hasConstantInvokeDynamic)
+                        ? readBootstrapMethodsAttribute(currentMaxStringLength)
+                        : null;
+    }
+
+    /**
+      * Constructs a new {@link ClassReader} object.
+      *
+      * @param inputStream an input stream of the JVMS ClassFile structure to be read. This input
+      *     stream must contain nothing more than the ClassFile structure itself. It is read from its
+      *     current position to its end.
+      * @throws IOException if a problem occurs during reading.
+      */
+    public ClassReader(final InputStream inputStream) throws IOException {
+        this(readStream(inputStream, false));
+    }
+
+    /**
+      * Constructs a new {@link ClassReader} object.
+      *
+      * @param className the fully qualified name of the class to be read. The ClassFile structure is
+      *     retrieved with the current class loader's {@link ClassLoader#getSystemResourceAsStream}.
+      * @throws IOException if an exception occurs during reading.
+      */
+    public ClassReader(final String className) throws IOException {
+        this(
+                readStream(
+                        ClassLoader.getSystemResourceAsStream(className.replace('.', '/') + ".class"), true));
+    }
+
+    /**
+      * Reads the given input stream and returns its content as a byte array.
+      *
+      * @param inputStream an input stream.
+      * @param close true to close the input stream after reading.
+      * @return the content of the given input stream.
+      * @throws IOException if a problem occurs during reading.
+      */
+    private static byte[] readStream(final InputStream inputStream, final boolean close)
+            throws IOException {
+        if (inputStream == null) {
+            throw new IOException("Class not found");
+        }
+        try {
+            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+            byte[] data = new byte[INPUT_STREAM_DATA_CHUNK_SIZE];
+            int bytesRead;
+            while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) {
+                outputStream.write(data, 0, bytesRead);
+            }
+            outputStream.flush();
+            return outputStream.toByteArray();
+        } finally {
+            if (close) {
+                inputStream.close();
+            }
+        }
+    }
+
+    // -----------------------------------------------------------------------------------------------
+    // Accessors
+    // -----------------------------------------------------------------------------------------------
+
+    /**
+      * Returns the class's access flags (see {@link Opcodes}). This value may not reflect Deprecated
+      * and Synthetic flags when bytecode is before 1.5 and those flags are represented by attributes.
+      *
+      * @return the class access flags.
+      * @see ClassVisitor#visit(int, int, String, String, String, String[])
+      */
     public int getAccess() {
         return readUnsignedShort(header);
     }
 
     /**
-     * Returns the internal name of the class (see
-     * {@link Type#getInternalName() getInternalName}).
-     *
-     * @return the internal class name
-     *
-     * @see ClassVisitor#visit(int, int, String, String, String, String[])
-     */
+      * Returns the internal name of the class (see {@link Type#getInternalName()}).
+      *
+      * @return the internal class name.
+      * @see ClassVisitor#visit(int, int, String, String, String, String[])
+      */
     public String getClassName() {
+        // this_class is just after the access_flags field (using 2 bytes).
         return readClass(header + 2, new char[maxStringLength]);
     }
 
     /**
-     * Returns the internal of name of the super class (see
-     * {@link Type#getInternalName() getInternalName}). For interfaces, the
-     * super class is {@link Object}.
-     *
-     * @return the internal name of super class, or <tt>null</tt> for
-     *         {@link Object} class.
-     *
-     * @see ClassVisitor#visit(int, int, String, String, String, String[])
-     */
+      * Returns the internal of name of the super class (see {@link Type#getInternalName()}). For
+      * interfaces, the super class is {@link Object}.
+      *
+      * @return the internal name of the super class, or {@literal null} for {@link Object} class.
+      * @see ClassVisitor#visit(int, int, String, String, String, String[])
+      */
     public String getSuperName() {
+        // super_class is after the access_flags and this_class fields (2 bytes each).
         return readClass(header + 4, new char[maxStringLength]);
     }
 
     /**
-     * Returns the internal names of the class's interfaces (see
-     * {@link Type#getInternalName() getInternalName}).
-     *
-     * @return the array of internal names for all implemented interfaces or
-     *         <tt>null</tt>.
-     *
-     * @see ClassVisitor#visit(int, int, String, String, String, String[])
-     */
+      * Returns the internal names of the implemented interfaces (see {@link Type#getInternalName()}).
+      *
+      * @return the internal names of the directly implemented interfaces. Inherited implemented
+      *     interfaces are not returned.
+      * @see ClassVisitor#visit(int, int, String, String, String, String[])
+      */
     public String[] getInterfaces() {
-        int index = header + 6;
-        int n = readUnsignedShort(index);
-        String[] interfaces = new String[n];
-        if (n > 0) {
-            char[] buf = new char[maxStringLength];
-            for (int i = 0; i < n; ++i) {
-                index += 2;
-                interfaces[i] = readClass(index, buf);
+        // interfaces_count is after the access_flags, this_class and super_class fields (2 bytes each).
+        int currentOffset = header + 6;
+        int interfacesCount = readUnsignedShort(currentOffset);
+        String[] interfaces = new String[interfacesCount];
+        if (interfacesCount > 0) {
+            char[] charBuffer = new char[maxStringLength];
+            for (int i = 0; i < interfacesCount; ++i) {
+                currentOffset += 2;
+                interfaces[i] = readClass(currentOffset, charBuffer);
             }
         }
         return interfaces;
     }
 
+    // -----------------------------------------------------------------------------------------------
+    // Public methods
+    // -----------------------------------------------------------------------------------------------
+
     /**
-     * Copies the constant pool data into the given {@link ClassWriter}. Should
-     * be called before the {@link #accept(ClassVisitor,int)} method.
-     *
-     * @param classWriter
-     *            the {@link ClassWriter} to copy constant pool into.
-     */
-    void copyPool(final ClassWriter classWriter) {
-        char[] buf = new char[maxStringLength];
-        int ll = items.length;
-        Item[] items2 = new Item[ll];
-        for (int i = 1; i < ll; i++) {
-            int index = items[i];
-            int tag = b[index - 1];
-            Item item = new Item(i);
-            int nameType;
-            switch (tag) {
-            case ClassWriter.FIELD:
-            case ClassWriter.METH:
-            case ClassWriter.IMETH:
-                nameType = items[readUnsignedShort(index + 2)];
-                item.set(tag, readClass(index, buf), readUTF8(nameType, buf),
-                        readUTF8(nameType + 2, buf));
-                break;
-            case ClassWriter.INT:
-                item.set(readInt(index));
-                break;
-            case ClassWriter.FLOAT:
-                item.set(Float.intBitsToFloat(readInt(index)));
-                break;
-            case ClassWriter.NAME_TYPE:
-                item.set(tag, readUTF8(index, buf), readUTF8(index + 2, buf),
-                        null);
-                break;
-            case ClassWriter.LONG:
-                item.set(readLong(index));
-                ++i;
-                break;
-            case ClassWriter.DOUBLE:
-                item.set(Double.longBitsToDouble(readLong(index)));
-                ++i;
-                break;
-            case ClassWriter.UTF8: {
-                String s = strings[i];
-                if (s == null) {
-                    index = items[i];
-                    s = strings[i] = readUTF(index + 2,
-                            readUnsignedShort(index), buf);
-                }
-                item.set(tag, s, null, null);
-                break;
-            }
-            case ClassWriter.HANDLE: {
-                int fieldOrMethodRef = items[readUnsignedShort(index + 1)];
-                nameType = items[readUnsignedShort(fieldOrMethodRef + 2)];
-                item.set(ClassWriter.HANDLE_BASE + readByte(index),
-                        readClass(fieldOrMethodRef, buf),
-                        readUTF8(nameType, buf), readUTF8(nameType + 2, buf));
-                break;
-            }
-            case ClassWriter.INDY:
-                if (classWriter.bootstrapMethods == null) {
-                    copyBootstrapMethods(classWriter, items2, buf);
-                }
-                nameType = items[readUnsignedShort(index + 2)];
-                item.set(readUTF8(nameType, buf), readUTF8(nameType + 2, buf),
-                        readUnsignedShort(index));
-                break;
-            // case ClassWriter.STR:
-            // case ClassWriter.CLASS:
-            // case ClassWriter.MTYPE:
-            // case ClassWriter.MODULE:
-            // case ClassWriter.PACKAGE:
-            default:
-                item.set(tag, readUTF8(index, buf), null, null);
-                break;
-            }
-
-            int index2 = item.hashCode % items2.length;
-            item.next = items2[index2];
-            items2[index2] = item;
-        }
-
-        int off = items[1] - 1;
-        classWriter.pool.putByteArray(b, off, header - off);
-        classWriter.items = items2;
-        classWriter.threshold = (int) (0.75d * ll);
-        classWriter.index = ll;
+      * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this
+      * {@link ClassReader}.
+      *
+      * @param classVisitor the visitor that must visit this class.
+      * @param parsingOptions the options to use to parse this class. One or more of {@link
+      *     #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}.
+      */
+    public void accept(final ClassVisitor classVisitor, final int parsingOptions) {
+        accept(classVisitor, new Attribute[0], parsingOptions);
     }
 
     /**
-     * Copies the bootstrap method data into the given {@link ClassWriter}.
-     * Should be called before the {@link #accept(ClassVisitor,int)} method.
-     *
-     * @param classWriter
-     *            the {@link ClassWriter} to copy bootstrap methods into.
-     */
-    private void copyBootstrapMethods(final ClassWriter classWriter,
-            final Item[] items, final char[] c) {
-        // finds the "BootstrapMethods" attribute
-        int u = getAttributes();
-        boolean found = false;
-        for (int i = readUnsignedShort(u); i > 0; --i) {
-            String attrName = readUTF8(u + 2, c);
-            if ("BootstrapMethods".equals(attrName)) {
-                found = true;
-                break;
+      * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this
+      * {@link ClassReader}.
+      *
+      * @param classVisitor the visitor that must visit this class.
+      * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of
+      *     the class. Any attribute whose type is not equal to the type of one the prototypes will not
+      *     be parsed: its byte array value will be passed unchanged to the ClassWriter. <i>This may
+      *     corrupt it if this value contains references to the constant pool, or has syntactic or
+      *     semantic links with a class element that has been transformed by a class adapter between
+      *     the reader and the writer</i>.
+      * @param parsingOptions the options to use to parse this class. One or more of {@link
+      *     #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}.
+      */
+    public void accept(
+            final ClassVisitor classVisitor,
+            final Attribute[] attributePrototypes,
+            final int parsingOptions) {
+        Context context = new Context();
+        context.attributePrototypes = attributePrototypes;
+        context.parsingOptions = parsingOptions;
+        context.charBuffer = new char[maxStringLength];
+
+        // Read the access_flags, this_class, super_class, interface_count and interfaces fields.
+        char[] charBuffer = context.charBuffer;
+        int currentOffset = header;
+        int accessFlags = readUnsignedShort(currentOffset);
+        String thisClass = readClass(currentOffset + 2, charBuffer);
+        String superClass = readClass(currentOffset + 4, charBuffer);
+        String[] interfaces = new String[readUnsignedShort(currentOffset + 6)];
+        currentOffset += 8;
+        for (int i = 0; i < interfaces.length; ++i) {
+            interfaces[i] = readClass(currentOffset, charBuffer);
+            currentOffset += 2;
+        }
+
+        // Read the class attributes (the variables are ordered as in Section 4.7 of the JVMS).
+        // Attribute offsets exclude the attribute_name_index and attribute_length fields.
+        // - The offset of the InnerClasses attribute, or 0.
+        int innerClassesOffset = 0;
+        // - The offset of the EnclosingMethod attribute, or 0.
+        int enclosingMethodOffset = 0;
+        // - The string corresponding to the Signature attribute, or null.
+        String signature = null;
+        // - The string corresponding to the SourceFile attribute, or null.
+        String sourceFile = null;
+        // - The string corresponding to the SourceDebugExtension attribute, or null.
+        String sourceDebugExtension = null;
+        // - The offset of the RuntimeVisibleAnnotations attribute, or 0.
+        int runtimeVisibleAnnotationsOffset = 0;
+        // - The offset of the RuntimeInvisibleAnnotations attribute, or 0.
+        int runtimeInvisibleAnnotationsOffset = 0;
+        // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0.
+        int runtimeVisibleTypeAnnotationsOffset = 0;
+        // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0.
+        int runtimeInvisibleTypeAnnotationsOffset = 0;
+        // - The offset of the Module attribute, or 0.
+        int moduleOffset = 0;
+        // - The offset of the ModulePackages attribute, or 0.
+        int modulePackagesOffset = 0;
+        // - The string corresponding to the ModuleMainClass attribute, or null.
+        String moduleMainClass = null;
+        // - The string corresponding to the NestHost attribute, or null.
+        String nestHostClass = null;
+        // - The offset of the NestMembers attribute, or 0.
+        int nestMembersOffset = 0;
+        // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
+        //   This list in the <i>reverse order</i> or their order in the ClassFile structure.
+        Attribute attributes = null;
+
+        int currentAttributeOffset = getFirstAttributeOffset();
+        for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
+            // Read the attribute_info's attribute_name and attribute_length fields.
+            String attributeName = readUTF8(currentAttributeOffset, charBuffer);
+            int attributeLength = readInt(currentAttributeOffset + 2);
+            currentAttributeOffset += 6;
+            // The tests are sorted in decreasing frequency order (based on frequencies observed on
+            // typical classes).
+            if (Constants.SOURCE_FILE.equals(attributeName)) {
+                sourceFile = readUTF8(currentAttributeOffset, charBuffer);
+            } else if (Constants.INNER_CLASSES.equals(attributeName)) {
+                innerClassesOffset = currentAttributeOffset;
+            } else if (Constants.ENCLOSING_METHOD.equals(attributeName)) {
+                enclosingMethodOffset = currentAttributeOffset;
+            } else if (Constants.NEST_HOST.equals(attributeName)) {
+                nestHostClass = readClass(currentAttributeOffset, charBuffer);
+            } else if (Constants.NEST_MEMBERS.equals(attributeName)) {
+                nestMembersOffset = currentAttributeOffset;
+            } else if (Constants.SIGNATURE.equals(attributeName)) {
+                signature = readUTF8(currentAttributeOffset, charBuffer);
+            } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
+                runtimeVisibleAnnotationsOffset = currentAttributeOffset;
+            } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
+                runtimeVisibleTypeAnnotationsOffset = currentAttributeOffset;
+            } else if (Constants.DEPRECATED.equals(attributeName)) {
+                accessFlags |= Opcodes.ACC_DEPRECATED;
+            } else if (Constants.SYNTHETIC.equals(attributeName)) {
+                accessFlags |= Opcodes.ACC_SYNTHETIC;
+            } else if (Constants.SOURCE_DEBUG_EXTENSION.equals(attributeName)) {
+                sourceDebugExtension =
+                        readUtf(currentAttributeOffset, attributeLength, new char[attributeLength]);
+            } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
+                runtimeInvisibleAnnotationsOffset = currentAttributeOffset;
+            } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
+                runtimeInvisibleTypeAnnotationsOffset = currentAttributeOffset;
+            } else if (Constants.MODULE.equals(attributeName)) {
+                moduleOffset = currentAttributeOffset;
+            } else if (Constants.MODULE_MAIN_CLASS.equals(attributeName)) {
+                moduleMainClass = readClass(currentAttributeOffset, charBuffer);
+            } else if (Constants.MODULE_PACKAGES.equals(attributeName)) {
+                modulePackagesOffset = currentAttributeOffset;
+            } else if (!Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
+                // The BootstrapMethods attribute is read in the constructor.
+                Attribute attribute =
+                        readAttribute(
+                                attributePrototypes,
+                                attributeName,
+                                currentAttributeOffset,
+                                attributeLength,
+                                charBuffer,
+                                -1,
+                                null);
+                attribute.nextAttribute = attributes;
+                attributes = attribute;
             }
-            u += 6 + readInt(u + 4);
+            currentAttributeOffset += attributeLength;
         }
-        if (!found) {
+
+        // Visit the class declaration. The minor_version and major_version fields start 6 bytes before
+        // the first constant pool entry, which itself starts at cpInfoOffsets[1] - 1 (by definition).
+        classVisitor.visit(
+                readInt(cpInfoOffsets[1] - 7), accessFlags, thisClass, signature, superClass, interfaces);
+
+        // Visit the SourceFile and SourceDebugExtenstion attributes.
+        if ((parsingOptions & SKIP_DEBUG) == 0
+                && (sourceFile != null || sourceDebugExtension != null)) {
+            classVisitor.visitSource(sourceFile, sourceDebugExtension);
+        }
+
+        // Visit the Module, ModulePackages and ModuleMainClass attributes.
+        if (moduleOffset != 0) {
+            readModuleAttributes(
+                    classVisitor, context, moduleOffset, modulePackagesOffset, moduleMainClass);
+        }
+
+        // Visit the NestHost attribute.
+        if (nestHostClass != null) {
+            classVisitor.visitNestHost(nestHostClass);
+        }
+
+        // Visit the EnclosingMethod attribute.
+        if (enclosingMethodOffset != 0) {
+            String className = readClass(enclosingMethodOffset, charBuffer);
+            int methodIndex = readUnsignedShort(enclosingMethodOffset + 2);
+            String name = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex], charBuffer);
+            String type = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex] + 2, charBuffer);
+            classVisitor.visitOuterClass(className, name, type);
+        }
+
+        // Visit the RuntimeVisibleAnnotations attribute.
+        if (runtimeVisibleAnnotationsOffset != 0) {
+            int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
+            int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
+            while (numAnnotations-- > 0) {
+                // Parse the type_index field.
+                String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+                currentAnnotationOffset += 2;
+                // Parse num_element_value_pairs and element_value_pairs and visit these values.
+                currentAnnotationOffset =
+                        readElementValues(
+                                classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
+                                currentAnnotationOffset,
+                                /* named = */ true,
+                                charBuffer);
+            }
+        }
+
+        // Visit the RuntimeInvisibleAnnotations attribute.
+        if (runtimeInvisibleAnnotationsOffset != 0) {
+            int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
+            int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
+            while (numAnnotations-- > 0) {
+                // Parse the type_index field.
+                String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+                currentAnnotationOffset += 2;
+                // Parse num_element_value_pairs and element_value_pairs and visit these values.
+                currentAnnotationOffset =
+                        readElementValues(
+                                classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
+                                currentAnnotationOffset,
+                                /* named = */ true,
+                                charBuffer);
+            }
+        }
+
+        // Visit the RuntimeVisibleTypeAnnotations attribute.
+        if (runtimeVisibleTypeAnnotationsOffset != 0) {
+            int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
+            int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
+            while (numAnnotations-- > 0) {
+                // Parse the target_type, target_info and target_path fields.
+                currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
+                // Parse the type_index field.
+                String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+                currentAnnotationOffset += 2;
+                // Parse num_element_value_pairs and element_value_pairs and visit these values.
+                currentAnnotationOffset =
+                        readElementValues(
+                                classVisitor.visitTypeAnnotation(
+                                        context.currentTypeAnnotationTarget,
+                                        context.currentTypeAnnotationTargetPath,
+                                        annotationDescriptor,
+                                        /* visible = */ true),
+                                currentAnnotationOffset,
+                                /* named = */ true,
+                                charBuffer);
+            }
+        }
+
+        // Visit the RuntimeInvisibleTypeAnnotations attribute.
+        if (runtimeInvisibleTypeAnnotationsOffset != 0) {
+            int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
+            int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
+            while (numAnnotations-- > 0) {
+                // Parse the target_type, target_info and target_path fields.
+                currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
+                // Parse the type_index field.
+                String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+                currentAnnotationOffset += 2;
+                // Parse num_element_value_pairs and element_value_pairs and visit these values.
+                currentAnnotationOffset =
+                        readElementValues(
+                                classVisitor.visitTypeAnnotation(
+                                        context.currentTypeAnnotationTarget,
+                                        context.currentTypeAnnotationTargetPath,
+                                        annotationDescriptor,
+                                        /* visible = */ false),
+                                currentAnnotationOffset,
+                                /* named = */ true,
+                                charBuffer);
+            }
+        }
+
+        // Visit the non standard attributes.
+        while (attributes != null) {
+            // Copy and reset the nextAttribute field so that it can also be used in ClassWriter.
+            Attribute nextAttribute = attributes.nextAttribute;
+            attributes.nextAttribute = null;
+            classVisitor.visitAttribute(attributes);
+            attributes = nextAttribute;
+        }
+
+        // Visit the NestedMembers attribute.
+        if (nestMembersOffset != 0) {
+            int numberOfNestMembers = readUnsignedShort(nestMembersOffset);
+            int currentNestMemberOffset = nestMembersOffset + 2;
+            while (numberOfNestMembers-- > 0) {
+                classVisitor.visitNestMember(readClass(currentNestMemberOffset, charBuffer));
+                currentNestMemberOffset += 2;
+            }
+        }
+
+        // Visit the InnerClasses attribute.
+        if (innerClassesOffset != 0) {
+            int numberOfClasses = readUnsignedShort(innerClassesOffset);
+            int currentClassesOffset = innerClassesOffset + 2;
+            while (numberOfClasses-- > 0) {
+                classVisitor.visitInnerClass(
+                        readClass(currentClassesOffset, charBuffer),
+                        readClass(currentClassesOffset + 2, charBuffer),
+                        readUTF8(currentClassesOffset + 4, charBuffer),
+                        readUnsignedShort(currentClassesOffset + 6));
+                currentClassesOffset += 8;
+            }
+        }
+
+        // Visit the fields and methods.
+        int fieldsCount = readUnsignedShort(currentOffset);
+        currentOffset += 2;
+        while (fieldsCount-- > 0) {
+            currentOffset = readField(classVisitor, context, currentOffset);
+        }
+        int methodsCount = readUnsignedShort(currentOffset);
+        currentOffset += 2;
+        while (methodsCount-- > 0) {
+            currentOffset = readMethod(classVisitor, context, currentOffset);
+        }
+
+        // Visit the end of the class.
+        classVisitor.visitEnd();
+    }
+
+    // ----------------------------------------------------------------------------------------------
+    // Methods to parse modules, fields and methods
+    // ----------------------------------------------------------------------------------------------
+
+    /**
+      * Reads the Module, ModulePackages and ModuleMainClass attributes and visit them.
+      *
+      * @param classVisitor the current class visitor
+      * @param context information about the class being parsed.
+      * @param moduleOffset the offset of the Module attribute (excluding the attribute_info's
+      *     attribute_name_index and attribute_length fields).
+      * @param modulePackagesOffset the offset of the ModulePackages attribute (excluding the
+      *     attribute_info's attribute_name_index and attribute_length fields), or 0.
+      * @param moduleMainClass the string corresponding to the ModuleMainClass attribute, or null.
+      */
+    private void readModuleAttributes(
+            final ClassVisitor classVisitor,
+            final Context context,
+            final int moduleOffset,
+            final int modulePackagesOffset,
+            final String moduleMainClass) {
+        char[] buffer = context.charBuffer;
+
+        // Read the module_name_index, module_flags and module_version_index fields and visit them.
+        int currentOffset = moduleOffset;
+        String moduleName = readModule(currentOffset, buffer);
+        int moduleFlags = readUnsignedShort(currentOffset + 2);
+        String moduleVersion = readUTF8(currentOffset + 4, buffer);
+        currentOffset += 6;
+        ModuleVisitor moduleVisitor = classVisitor.visitModule(moduleName, moduleFlags, moduleVersion);
+        if (moduleVisitor == null) {
             return;
         }
-        // copies the bootstrap methods in the class writer
-        int boostrapMethodCount = readUnsignedShort(u + 8);
-        for (int j = 0, v = u + 10; j < boostrapMethodCount; j++) {
-            int position = v - u - 10;
-            int hashCode = readConst(readUnsignedShort(v), c).hashCode();
-            for (int k = readUnsignedShort(v + 2); k > 0; --k) {
-                hashCode ^= readConst(readUnsignedShort(v + 4), c).hashCode();
-                v += 2;
+
+        // Visit the ModuleMainClass attribute.
+        if (moduleMainClass != null) {
+            moduleVisitor.visitMainClass(moduleMainClass);
+        }
+
+        // Visit the ModulePackages attribute.
+        if (modulePackagesOffset != 0) {
+            int packageCount = readUnsignedShort(modulePackagesOffset);
+            int currentPackageOffset = modulePackagesOffset + 2;
+            while (packageCount-- > 0) {
+                moduleVisitor.visitPackage(readPackage(currentPackageOffset, buffer));
+                currentPackageOffset += 2;
             }
-            v += 4;
-            Item item = new Item(j);
-            item.set(position, hashCode & 0x7FFFFFFF);
-            int index = item.hashCode % items.length;
-            item.next = items[index];
-            items[index] = item;
         }
-        int attrSize = readInt(u + 4);
-        ByteVector bootstrapMethods = new ByteVector(attrSize + 62);
-        bootstrapMethods.putByteArray(b, u + 10, attrSize - 2);
-        classWriter.bootstrapMethodsCount = boostrapMethodCount;
-        classWriter.bootstrapMethods = bootstrapMethods;
+
+        // Read the 'requires_count' and 'requires' fields.
+        int requiresCount = readUnsignedShort(currentOffset);
+        currentOffset += 2;
+        while (requiresCount-- > 0) {
+            // Read the requires_index, requires_flags and requires_version fields and visit them.
+            String requires = readModule(currentOffset, buffer);
+            int requiresFlags = readUnsignedShort(currentOffset + 2);
+            String requiresVersion = readUTF8(currentOffset + 4, buffer);
+            currentOffset += 6;
+            moduleVisitor.visitRequire(requires, requiresFlags, requiresVersion);
+        }
+
+        // Read the 'exports_count' and 'exports' fields.
+        int exportsCount = readUnsignedShort(currentOffset);
+        currentOffset += 2;
+        while (exportsCount-- > 0) {
+            // Read the exports_index, exports_flags, exports_to_count and exports_to_index fields
+            // and visit them.
+            String exports = readPackage(currentOffset, buffer);
+            int exportsFlags = readUnsignedShort(currentOffset + 2);
+            int exportsToCount = readUnsignedShort(currentOffset + 4);
+            currentOffset += 6;
+            String[] exportsTo = null;
+            if (exportsToCount != 0) {
+                exportsTo = new String[exportsToCount];
+                for (int i = 0; i < exportsToCount; ++i) {
+                    exportsTo[i] = readModule(currentOffset, buffer);
+                    currentOffset += 2;
+                }
+            }
+            moduleVisitor.visitExport(exports, exportsFlags, exportsTo);
+        }
+
+        // Reads the 'opens_count' and 'opens' fields.
+        int opensCount = readUnsignedShort(currentOffset);
+        currentOffset += 2;
+        while (opensCount-- > 0) {
+            // Read the opens_index, opens_flags, opens_to_count and opens_to_index fields and visit them.
+            String opens = readPackage(currentOffset, buffer);
+            int opensFlags = readUnsignedShort(currentOffset + 2);
+            int opensToCount = readUnsignedShort(currentOffset + 4);
+            currentOffset += 6;
+            String[] opensTo = null;
+            if (opensToCount != 0) {
+                opensTo = new String[opensToCount];
+                for (int i = 0; i < opensToCount; ++i) {
+                    opensTo[i] = readModule(currentOffset, buffer);
+                    currentOffset += 2;
+                }
+            }
+            moduleVisitor.visitOpen(opens, opensFlags, opensTo);
+        }
+
+        // Read the 'uses_count' and 'uses' fields.
+        int usesCount = readUnsignedShort(currentOffset);
+        currentOffset += 2;
+        while (usesCount-- > 0) {
+            moduleVisitor.visitUse(readClass(currentOffset, buffer));
+            currentOffset += 2;
+        }
+
+        // Read the  'provides_count' and 'provides' fields.
+        int providesCount = readUnsignedShort(currentOffset);
+        currentOffset += 2;
+        while (providesCount-- > 0) {
+            // Read the provides_index, provides_with_count and provides_with_index fields and visit them.
+            String provides = readClass(currentOffset, buffer);
+            int providesWithCount = readUnsignedShort(currentOffset + 2);
+            currentOffset += 4;
+            String[] providesWith = new String[providesWithCount];
+            for (int i = 0; i < providesWithCount; ++i) {
+                providesWith[i] = readClass(currentOffset, buffer);
+                currentOffset += 2;
+            }
+            moduleVisitor.visitProvide(provides, providesWith);
+        }
+
+        // Visit the end of the module attributes.
+        moduleVisitor.visitEnd();
     }
 
     /**
-     * Constructs a new {@link ClassReader} object.
-     *
-     * @param is
-     *            an input stream from which to read the class.
-     * @throws IOException
-     *             if a problem occurs during reading.
-     */
-    public ClassReader(final InputStream is) throws IOException {
-        this(readClass(is, false));
+      * Reads a JVMS field_info structure and makes the given visitor visit it.
+      *
+      * @param classVisitor the visitor that must visit the field.
+      * @param context information about the class being parsed.
+      * @param fieldInfoOffset the start offset of the field_info structure.
+      * @return the offset of the first byte following the field_info structure.
+      */
+    private int readField(
+            final ClassVisitor classVisitor, final Context context, final int fieldInfoOffset) {
+        char[] charBuffer = context.charBuffer;
+
+        // Read the access_flags, name_index and descriptor_index fields.
+        int currentOffset = fieldInfoOffset;
+        int accessFlags = readUnsignedShort(currentOffset);
+        String name = readUTF8(currentOffset + 2, charBuffer);
+        String descriptor = readUTF8(currentOffset + 4, charBuffer);
+        currentOffset += 6;
+
+        // Read the field attributes (the variables are ordered as in Section 4.7 of the JVMS).
+        // Attribute offsets exclude the attribute_name_index and attribute_length fields.
+        // - The value corresponding to the ConstantValue attribute, or null.
+        Object constantValue = null;
+        // - The string corresponding to the Signature attribute, or null.
+        String signature = null;
+        // - The offset of the RuntimeVisibleAnnotations attribute, or 0.
+        int runtimeVisibleAnnotationsOffset = 0;
+        // - The offset of the RuntimeInvisibleAnnotations attribute, or 0.
+        int runtimeInvisibleAnnotationsOffset = 0;
+        // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0.
+        int runtimeVisibleTypeAnnotationsOffset = 0;
+        // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0.
+        int runtimeInvisibleTypeAnnotationsOffset = 0;
+        // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
+        //   This list in the <i>reverse order</i> or their order in the ClassFile structure.
+        Attribute attributes = null;
+
+        int attributesCount = readUnsignedShort(currentOffset);
+        currentOffset += 2;
+        while (attributesCount-- > 0) {
+            // Read the attribute_info's attribute_name and attribute_length fields.
+            String attributeName = readUTF8(currentOffset, charBuffer);
+            int attributeLength = readInt(currentOffset + 2);
+            currentOffset += 6;
+            // The tests are sorted in decreasing frequency order (based on frequencies observed on
+            // typical classes).
+            if (Constants.CONSTANT_VALUE.equals(attributeName)) {
+                int constantvalueIndex = readUnsignedShort(currentOffset);
+                constantValue = constantvalueIndex == 0 ? null : readConst(constantvalueIndex, charBuffer);
+            } else if (Constants.SIGNATURE.equals(attributeName)) {
+                signature = readUTF8(currentOffset, charBuffer);
+            } else if (Constants.DEPRECATED.equals(attributeName)) {
+                accessFlags |= Opcodes.ACC_DEPRECATED;
+            } else if (Constants.SYNTHETIC.equals(attributeName)) {
+                accessFlags |= Opcodes.ACC_SYNTHETIC;
+            } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
+                runtimeVisibleAnnotationsOffset = currentOffset;
+            } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
+                runtimeVisibleTypeAnnotationsOffset = currentOffset;
+            } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
+                runtimeInvisibleAnnotationsOffset = currentOffset;
+            } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
+                runtimeInvisibleTypeAnnotationsOffset = currentOffset;
+            } else {
+                Attribute attribute =
+                        readAttribute(
+                                context.attributePrototypes,
+                                attributeName,
+                                currentOffset,
+                                attributeLength,
+                                charBuffer,
+                                -1,
+                                null);
+                attribute.nextAttribute = attributes;
+                attributes = attribute;
+            }
+            currentOffset += attributeLength;
+        }
+
+        // Visit the field declaration.
+        FieldVisitor fieldVisitor =
+                classVisitor.visitField(accessFlags, name, descriptor, signature, constantValue);
+        if (fieldVisitor == null) {
+            return currentOffset;
+        }
+
+        // Visit the RuntimeVisibleAnnotations attribute.
+        if (runtimeVisibleAnnotationsOffset != 0) {
+            int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
+            int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
+            while (numAnnotations-- > 0) {
+                // Parse the type_index field.
+                String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+                currentAnnotationOffset += 2;
+                // Parse num_element_value_pairs and element_value_pairs and visit these values.
+                currentAnnotationOffset =
+                        readElementValues(
+                                fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
+                                currentAnnotationOffset,
+                                /* named = */ true,
+                                charBuffer);
+            }
+        }
+
+        // Visit the RuntimeInvisibleAnnotations attribute.
+        if (runtimeInvisibleAnnotationsOffset != 0) {
+            int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
+            int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
+            while (numAnnotations-- > 0) {
+                // Parse the type_index field.
+                String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+                currentAnnotationOffset += 2;
+                // Parse num_element_value_pairs and element_value_pairs and visit these values.
+                currentAnnotationOffset =
+                        readElementValues(
+                                fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
+                                currentAnnotationOffset,
+                                /* named = */ true,
+                                charBuffer);
+            }
+        }
+
+        // Visit the RuntimeVisibleTypeAnnotations attribute.
+        if (runtimeVisibleTypeAnnotationsOffset != 0) {
+            int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
+            int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
+            while (numAnnotations-- > 0) {
+                // Parse the target_type, target_info and target_path fields.
+                currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
+                // Parse the type_index field.
+                String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+                currentAnnotationOffset += 2;
+                // Parse num_element_value_pairs and element_value_pairs and visit these values.
+                currentAnnotationOffset =
+                        readElementValues(
+                                fieldVisitor.visitTypeAnnotation(
+                                        context.currentTypeAnnotationTarget,
+                                        context.currentTypeAnnotationTargetPath,
+                                        annotationDescriptor,
+                                        /* visible = */ true),
+                                currentAnnotationOffset,
+                                /* named = */ true,
+                                charBuffer);
+            }
+        }
+
+        // Visit the RuntimeInvisibleTypeAnnotations attribute.
+        if (runtimeInvisibleTypeAnnotationsOffset != 0) {
+            int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
+            int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
+            while (numAnnotations-- > 0) {
+                // Parse the target_type, target_info and target_path fields.
+                currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
+                // Parse the type_index field.
+                String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+                currentAnnotationOffset += 2;
+                // Parse num_element_value_pairs and element_value_pairs and visit these values.
+                currentAnnotationOffset =
+                        readElementValues(
+                                fieldVisitor.visitTypeAnnotation(
+                                        context.currentTypeAnnotationTarget,
+                                        context.currentTypeAnnotationTargetPath,
+                                        annotationDescriptor,
+                                        /* visible = */ false),
+                                currentAnnotationOffset,
+                                /* named = */ true,
+                                charBuffer);
+            }
+        }
+
+        // Visit the non standard attributes.
+        while (attributes != null) {
+            // Copy and reset the nextAttribute field so that it can also be used in FieldWriter.
+            Attribute nextAttribute = attributes.nextAttribute;
+            attributes.nextAttribute = null;
+            fieldVisitor.visitAttribute(attributes);
+            attributes = nextAttribute;
+        }
+
+        // Visit the end of the field.
+        fieldVisitor.visitEnd();
+        return currentOffset;
     }
 
     /**
-     * Constructs a new {@link ClassReader} object.
-     *
-     * @param name
-     *            the binary qualified name of the class to be read.
-     * @throws IOException
-     *             if an exception occurs during reading.
-     */
-    public ClassReader(final String name) throws IOException {
-        this(readClass(
-                ClassLoader.getSystemResourceAsStream(name.replace('.', '/')
-                        + ".class"), true));
-    }
+      * Reads a JVMS method_info structure and makes the given visitor visit it.
+      *
+      * @param classVisitor the visitor that must visit the method.
+      * @param context information about the class being parsed.
+      * @param methodInfoOffset the start offset of the method_info structure.
+      * @return the offset of the first byte following the method_info structure.
+      */
+    private int readMethod(
+            final ClassVisitor classVisitor, final Context context, final int methodInfoOffset) {
+        char[] charBuffer = context.charBuffer;
 
-    /**
-     * Reads the bytecode of a class.
-     *
-     * @param is
-     *            an input stream from which to read the class.
-     * @param close
-     *            true to close the input stream after reading.
-     * @return the bytecode read from the given input stream.
-     * @throws IOException
-     *             if a problem occurs during reading.
-     */
-    private static byte[] readClass(final InputStream is, boolean close)
-            throws IOException {
-        if (is == null) {
-            throw new IOException("Class not found");
-        }
-        try {
-            byte[] b = new byte[is.available()];
-            int len = 0;
-            while (true) {
-                int n = is.read(b, len, b.length - len);
-                if (n == -1) {
-                    if (len < b.length) {
-                        byte[] c = new byte[len];
-                        System.arraycopy(b, 0, c, 0, len);
-                        b = c;
-                    }
-                    return b;
+        // Read the access_flags, name_index and descriptor_index fields.
+        int currentOffset = methodInfoOffset;
+        context.currentMethodAccessFlags = readUnsignedShort(currentOffset);
+        context.currentMethodName = readUTF8(currentOffset + 2, charBuffer);
+        context.currentMethodDescriptor = readUTF8(currentOffset + 4, charBuffer);
+        currentOffset += 6;
+
+        // Read the method attributes (the variables are ordered as in Section 4.7 of the JVMS).
+        // Attribute offsets exclude the attribute_name_index and attribute_length fields.
+        // - The offset of the Code attribute, or 0.
+        int codeOffset = 0;
+        // - The offset of the Exceptions attribute, or 0.
+        int exceptionsOffset = 0;
+        // - The strings corresponding to the Exceptions attribute, or null.
+        String[] exceptions = null;
+        // - Whether the method has a Synthetic attribute.
+        boolean synthetic = false;
+        // - The constant pool index contained in the Signature attribute, or 0.
+        int signatureIndex = 0;
+        // - The offset of the RuntimeVisibleAnnotations attribute, or 0.
+        int runtimeVisibleAnnotationsOffset = 0;
+        // - The offset of the RuntimeInvisibleAnnotations attribute, or 0.
+        int runtimeInvisibleAnnotationsOffset = 0;
+        // - The offset of the RuntimeVisibleParameterAnnotations attribute, or 0.
+        int runtimeVisibleParameterAnnotationsOffset = 0;
+        // - The offset of the RuntimeInvisibleParameterAnnotations attribute, or 0.
+        int runtimeInvisibleParameterAnnotationsOffset = 0;
+        // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0.
+        int runtimeVisibleTypeAnnotationsOffset = 0;
+        // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0.
+        int runtimeInvisibleTypeAnnotationsOffset = 0;
+        // - The offset of the AnnotationDefault attribute, or 0.
+        int annotationDefaultOffset = 0;
+        // - The offset of the MethodParameters attribute, or 0.
+        int methodParametersOffset = 0;
+        // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
+        //   This list in the <i>reverse order</i> or their order in the ClassFile structure.
+        Attribute attributes = null;
+
+        int attributesCount = readUnsignedShort(currentOffset);
+        currentOffset += 2;
+        while (attributesCount-- > 0) {
+            // Read the attribute_info's attribute_name and attribute_length fields.
+            String attributeName = readUTF8(currentOffset, charBuffer);
+            int attributeLength = readInt(currentOffset + 2);
+            currentOffset += 6;
+            // The tests are sorted in decreasing frequency order (based on frequencies observed on
+            // typical classes).
+            if (Constants.CODE.equals(attributeName)) {
+                if ((context.parsingOptions & SKIP_CODE) == 0) {
+                    codeOffset = currentOffset;
                 }
-                len += n;
-                if (len == b.length) {
-                    int last = is.read();
-                    if (last < 0) {
-                        return b;
-                    }
-                    byte[] c = new byte[b.length + 1000];
-                    System.arraycopy(b, 0, c, 0, len);
-                    c[len++] = (byte) last;
-                    b = c;
+            } else if (Constants.EXCEPTIONS.equals(attributeName)) {
+                exceptionsOffset = currentOffset;
+                exceptions = new String[readUnsignedShort(exceptionsOffset)];
+                int currentExceptionOffset = exceptionsOffset + 2;
+                for (int i = 0; i < exceptions.length; ++i) {
+                    exceptions[i] = readClass(currentExceptionOffset, charBuffer);
+                    currentExceptionOffset += 2;
                 }
+            } else if (Constants.SIGNATURE.equals(attributeName)) {
+                signatureIndex = readUnsignedShort(currentOffset);
+            } else if (Constants.DEPRECATED.equals(attributeName)) {
+                context.currentMethodAccessFlags |= Opcodes.ACC_DEPRECATED;
+            } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
+                runtimeVisibleAnnotationsOffset = currentOffset;
+            } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
+                runtimeVisibleTypeAnnotationsOffset = currentOffset;
+            } else if (Constants.ANNOTATION_DEFAULT.equals(attributeName)) {
+                annotationDefaultOffset = currentOffset;
+            } else if (Constants.SYNTHETIC.equals(attributeName)) {
+                synthetic = true;
+                context.currentMethodAccessFlags |= Opcodes.ACC_SYNTHETIC;
+            } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
+                runtimeInvisibleAnnotationsOffset = currentOffset;
+            } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
+                runtimeInvisibleTypeAnnotationsOffset = currentOffset;
+            } else if (Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) {
+                runtimeVisibleParameterAnnotationsOffset = currentOffset;
+            } else if (Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) {
+                runtimeInvisibleParameterAnnotationsOffset = currentOffset;
+            } else if (Constants.METHOD_PARAMETERS.equals(attributeName)) {
+                methodParametersOffset = currentOffset;
+            } else {
+                Attribute attribute =
+                        readAttribute(
+                                context.attributePrototypes,
+                                attributeName,
+                                currentOffset,
+                                attributeLength,
+                                charBuffer,
+                                -1,
+                                null);
+                attribute.nextAttribute = attributes;
+                attributes = attribute;
             }
-        } finally {
-            if (close) {
-                is.close();
-            }
-        }
-    }
-
-    // ------------------------------------------------------------------------
-    // Public methods
-    // ------------------------------------------------------------------------
-
-    /**
-     * Makes the given visitor visit the Java class of this {@link ClassReader}
-     * . This class is the one specified in the constructor (see
-     * {@link #ClassReader(byte[]) ClassReader}).
-     *
-     * @param classVisitor
-     *            the visitor that must visit this class.
-     * @param flags
-     *            option flags that can be used to modify the default behavior
-     *            of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}
-     *            , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}.
-     */
-    public void accept(final ClassVisitor classVisitor, final int flags) {
-        accept(classVisitor, Attribute.DEFAULT_ATTRIBUTE_PROTOS, flags);
-    }
-
-    /**
-     * Makes the given visitor visit the Java class of this {@link ClassReader}.
-     * This class is the one specified in the constructor (see
-     * {@link #ClassReader(byte[]) ClassReader}).
-     *
-     * @param classVisitor
-     *            the visitor that must visit this class.
-     * @param attrs
-     *            prototypes of the attributes that must be parsed during the
-     *            visit of the class. Any attribute whose type is not equal to
-     *            the type of one the prototypes will not be parsed: its byte
-     *            array value will be passed unchanged to the ClassWriter.
-     *            <i>This may corrupt it if this value contains references to
-     *            the constant pool, or has syntactic or semantic links with a
-     *            class element that has been transformed by a class adapter
-     *            between the reader and the writer</i>.
-     * @param flags
-     *            option flags that can be used to modify the default behavior
-     *            of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}
-     *            , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}.
-     */
-    public void accept(final ClassVisitor classVisitor,
-            final Attribute[] attrs, final int flags) {
-        int u = header; // current offset in the class file
-        char[] c = new char[maxStringLength]; // buffer used to read strings
-
-        Context context = new Context();
-        context.attrs = attrs;
-        context.flags = flags;
-        context.buffer = c;
-
-        // reads the class declaration
-        int access = readUnsignedShort(u);
-        String name = readClass(u + 2, c);
-        String superClass = readClass(u + 4, c);
-        String[] interfaces = new String[readUnsignedShort(u + 6)];
-        u += 8;
-        for (int i = 0; i < interfaces.length; ++i) {
-            interfaces[i] = readClass(u, c);
-            u += 2;
+            currentOffset += attributeLength;
         }
 
-        // reads the class attributes
-        String signature = null;
-        String sourceFile = null;
-        String sourceDebug = null;
-        String enclosingOwner = null;
-        String enclosingName = null;
-        String enclosingDesc = null;
-        String moduleMainClass = null;
-        int anns = 0;
-        int ianns = 0;
-        int tanns = 0;
-        int itanns = 0;
-        int innerClasses = 0;
-        int module = 0;
-        int packages = 0;
-        Attribute attributes = null;
-
-        u = getAttributes();
-        for (int i = readUnsignedShort(u); i > 0; --i) {
-            String attrName = readUTF8(u + 2, c);
-            // tests are sorted in decreasing frequency order
-            // (based on frequencies observed on typical classes)
-            if ("SourceFile".equals(attrName)) {
-                sourceFile = readUTF8(u + 8, c);
-            } else if ("InnerClasses".equals(attrName)) {
-                innerClasses = u + 8;
-            } else if ("EnclosingMethod".equals(attrName)) {
-                enclosingOwner = readClass(u + 8, c);
-                int item = readUnsignedShort(u + 10);
-                if (item != 0) {
-                    enclosingName = readUTF8(items[item], c);
-                    enclosingDesc = readUTF8(items[item] + 2, c);
-                }
-            } else if ("Signature".equals(attrName)) {
-                signature = readUTF8(u + 8, c);
-            } else if ("RuntimeVisibleAnnotations".equals(attrName)) {
-                anns = u + 8;
-            } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
-                tanns = u + 8;
-            } else if ("Deprecated".equals(attrName)) {
-                access |= Opcodes.ACC_DEPRECATED;
-            } else if ("Synthetic".equals(attrName)) {
-                access |= Opcodes.ACC_SYNTHETIC
-                        | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
-            } else if ("SourceDebugExtension".equals(attrName)) {
-                int len = readInt(u + 4);
-                sourceDebug = readUTF(u + 8, len, new char[len]);
-            } else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
-                ianns = u + 8;
-            } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
-                itanns = u + 8;
-            } else if ("Module".equals(attrName)) {
-                module = u + 8;
-            } else if ("ModuleMainClass".equals(attrName)) {
-                moduleMainClass = readClass(u + 8, c);
-            } else if ("ModulePackages".equals(attrName)) {
-                packages = u + 10;
-            } else if ("BootstrapMethods".equals(attrName)) {
-                int[] bootstrapMethods = new int[readUnsignedShort(u + 8)];
-                for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) {
-                    bootstrapMethods[j] = v;
-                    v += 2 + readUnsignedShort(v + 2) << 1;
-                }
-                context.bootstrapMethods = bootstrapMethods;
-            } else {
-                Attribute attr = readAttribute(attrs, attrName, u + 8,
-                        readInt(u + 4), c, -1, null);
-                if (attr != null) {
-                    attr.next = attributes;
-                    attributes = attr;
-                }
-            }
-            u += 6 + readInt(u + 4);
+        // Visit the method declaration.
+        MethodVisitor methodVisitor =
+                classVisitor.visitMethod(
+                        context.currentMethodAccessFlags,
+                        context.currentMethodName,
+                        context.currentMethodDescriptor,
+                        signatureIndex == 0 ? null : readUtf(signatureIndex, charBuffer),
+                        exceptions);
+        if (methodVisitor == null) {
+            return currentOffset;
         }
 
-        // visits the class declaration
-        classVisitor.visit(readInt(items[1] - 7), access, name, signature,
-                superClass, interfaces);
-
-        // visits the source and debug info
-        if ((flags & SKIP_DEBUG) == 0
-                && (sourceFile != null || sourceDebug != null)) {
-            classVisitor.visitSource(sourceFile, sourceDebug);
-        }
-
-        // visits the module info and associated attributes
-        if (module != 0) {
-            readModule(classVisitor, context, module,
-                    moduleMainClass, packages);
-        }
-
-        // visits the outer class
-        if (enclosingOwner != null) {
-            classVisitor.visitOuterClass(enclosingOwner, enclosingName,
-                    enclosingDesc);
-        }
-
-        // visits the class annotations and type annotations
-        if (anns != 0) {
-            for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
-                v = readAnnotationValues(v + 2, c, true,
-                        classVisitor.visitAnnotation(readUTF8(v, c), true));
-            }
-        }
-        if (ianns != 0) {
-            for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
-                v = readAnnotationValues(v + 2, c, true,
-                        classVisitor.visitAnnotation(readUTF8(v, c), false));
-            }
-        }
-        if (tanns != 0) {
-            for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
-                v = readAnnotationTarget(context, v);
-                v = readAnnotationValues(v + 2, c, true,
-                        classVisitor.visitTypeAnnotation(context.typeRef,
-                                context.typePath, readUTF8(v, c), true));
-            }
-        }
-        if (itanns != 0) {
-            for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
-                v = readAnnotationTarget(context, v);
-                v = readAnnotationValues(v + 2, c, true,
-                        classVisitor.visitTypeAnnotation(context.typeRef,
-                                context.typePath, readUTF8(v, c), false));
+        // If the returned MethodVisitor is in fact a MethodWriter, it means there is no method
+        // adapter between the reader and the writer. In this case, it might be possible to copy
+        // the method attributes directly into the writer. If so, return early without visiting
+        // the content of these attributes.
+        if (methodVisitor instanceof MethodWriter) {
+            MethodWriter methodWriter = (MethodWriter) methodVisitor;
+            if (methodWriter.canCopyMethodAttributes(
+                    this,
+                    methodInfoOffset,
+                    currentOffset - methodInfoOffset,
+                    synthetic,
+                    (context.currentMethodAccessFlags & Opcodes.ACC_DEPRECATED) != 0,
+                    readUnsignedShort(methodInfoOffset + 4),
+                    signatureIndex,
+                    exceptionsOffset)) {
+                return currentOffset;
             }
         }
 
-        // visits the attributes
-        while (attributes != null) {
-            Attribute attr = attributes.next;
-            attributes.next = null;
-            classVisitor.visitAttribute(attributes);
-            attributes = attr;
-        }
-
-        // visits the inner classes
-        if (innerClasses != 0) {
-            int v = innerClasses + 2;
-            for (int i = readUnsignedShort(innerClasses); i > 0; --i) {
-                classVisitor.visitInnerClass(readClass(v, c),
-                        readClass(v + 2, c), readUTF8(v + 4, c),
-                        readUnsignedShort(v + 6));
-                v += 8;
+        // Visit the MethodParameters attribute.
+        if (methodParametersOffset != 0) {
+            int parametersCount = readByte(methodParametersOffset);
+            int currentParameterOffset = methodParametersOffset + 1;
+            while (parametersCount-- > 0) {
+                // Read the name_index and access_flags fields and visit them.
+                methodVisitor.visitParameter(
+                        readUTF8(currentParameterOffset, charBuffer),
+                        readUnsignedShort(currentParameterOffset + 2));
+                currentParameterOffset += 4;
             }
         }
 
-        // visits the fields and methods
-        u = header + 10 + 2 * interfaces.length;
-        for (int i = readUnsignedShort(u - 2); i > 0; --i) {
-            u = readField(classVisitor, context, u);
-        }
-        u += 2;
-        for (int i = readUnsignedShort(u - 2); i > 0; --i) {
-            u = readMethod(classVisitor, context, u);
-        }
-
-        // visits the end of the class
-        classVisitor.visitEnd();
-    }
-
-    /**
-     * Reads the module attribute and visit it.
-     *
-     * @param classVisitor
-     *           the current class visitor
-     * @param context
-     *           information about the class being parsed.
-     * @param u
-     *           start offset of the module attribute in the class file.
-     * @param mainClass
-     *           name of the main class of a module or null.
-     * @param packages
-     *           start offset of the concealed package attribute.
-     */
-    private void readModule(final ClassVisitor classVisitor,
-            final Context context, int u,
-            final String mainClass, int packages) {
-
-        char[] buffer = context.buffer;
-
-        // reads module name, flags and version
-        String name = readModule(u, buffer);
-        int flags = readUnsignedShort(u + 2);
-        String version = readUTF8(u + 4, buffer);
-        u += 6;
-
-        ModuleVisitor mv = classVisitor.visitModule(name, flags, version);
-        if (mv == null) {
-            return;
-        }
-
-        // module attributes (main class, packages)
-        if (mainClass != null) {
-            mv.visitMainClass(mainClass);
-        }
-
-        if (packages != 0) {
-            for (int i = readUnsignedShort(packages - 2); i > 0; --i) {
-                String packaze = readPackage(packages, buffer);
-                mv.visitPackage(packaze);
-                packages += 2;
+        // Visit the AnnotationDefault attribute.
+        if (annotationDefaultOffset != 0) {
+            AnnotationVisitor annotationVisitor = methodVisitor.visitAnnotationDefault();
+            readElementValue(annotationVisitor, annotationDefaultOffset, null, charBuffer);
+            if (annotationVisitor != null) {
+                annotationVisitor.visitEnd();
             }
         }
 
-        // reads requires
-        u += 2;
-        for (int i = readUnsignedShort(u - 2); i > 0; --i) {
-            String module = readModule(u, buffer);
-            int access = readUnsignedShort(u + 2);
-            String requireVersion = readUTF8(u + 4, buffer);
-            mv.visitRequire(module, access, requireVersion);
-            u += 6;
-        }
-
-        // reads exports
-        u += 2;
-        for (int i = readUnsignedShort(u - 2); i > 0; --i) {
-            String export = readPackage(u, buffer);
-            int access = readUnsignedShort(u + 2);
-            int exportToCount = readUnsignedShort(u + 4);
-            u += 6;
-            String[] tos = null;
-            if (exportToCount != 0) {
-                tos = new String[exportToCount];
-                for (int j = 0; j < tos.length; ++j) {
-                    tos[j] = readModule(u, buffer);
-                    u += 2;
-                }
-            }
-            mv.visitExport(export, access, tos);
-        }
-
-        // reads opens
-        u += 2;
-        for (int i = readUnsignedShort(u - 2); i > 0; --i) {
-            String open = readPackage(u, buffer);
-            int access = readUnsignedShort(u + 2);
-            int openToCount = readUnsignedShort(u + 4);
-            u += 6;
-            String[] tos = null;
-            if (openToCount != 0) {
-                tos = new String[openToCount];
-                for (int j = 0; j < tos.length; ++j) {
-                    tos[j] = readModule(u, buffer);
-                    u += 2;
-                }
-            }
-            mv.visitOpen(open, access, tos);
-        }
-
-        // read uses
-        u += 2;
-        for (int i = readUnsignedShort(u - 2); i > 0; --i) {
-            mv.visitUse(readClass(u, buffer));
-            u += 2;
-        }
-
-        // read provides
-        u += 2;
-        for (int i = readUnsignedShort(u - 2); i > 0; --i) {
-            String service = readClass(u, buffer);
-            int provideWithCount = readUnsignedShort(u + 2);
-            u += 4;
-            String[] withs = new String[provideWithCount];
-            for (int j = 0; j < withs.length; ++j) {
-                withs[j] = readClass(u, buffer);
-                u += 2;
-            }
-            mv.visitProvide(service, withs);
-        }
-
-        mv.visitEnd();
-    }
-
-    /**
-     * Reads a field and makes the given visitor visit it.
-     *
-     * @param classVisitor
-     *            the visitor that must visit the field.
-     * @param context
-     *            information about the class being parsed.
-     * @param u
-     *            the start offset of the field in the class file.
-     * @return the offset of the first byte following the field in the class.
-     */
-    private int readField(final ClassVisitor classVisitor,
-            final Context context, int u) {
-        // reads the field declaration
-        char[] c = context.buffer;
-        int access = readUnsignedShort(u);
-        String name = readUTF8(u + 2, c);
-        String desc = readUTF8(u + 4, c);
-        u += 6;
-
-        // reads the field attributes
-        String signature = null;
-        int anns = 0;
-        int ianns = 0;
-        int tanns = 0;
-        int itanns = 0;
-        Object value = null;
-        Attribute attributes = null;
-
-        for (int i = readUnsignedShort(u); i > 0; --i) {
-            String attrName = readUTF8(u + 2, c);
-            // tests are sorted in decreasing frequency order
-            // (based on frequencies observed on typical classes)
-            if ("ConstantValue".equals(attrName)) {
-                int item = readUnsignedShort(u + 8);
-                value = item == 0 ? null : readConst(item, c);
-            } else if ("Signature".equals(attrName)) {
-                signature = readUTF8(u + 8, c);
-            } else if ("Deprecated".equals(attrName)) {
-                access |= Opcodes.ACC_DEPRECATED;
-            } else if ("Synthetic".equals(attrName)) {
-                access |= Opcodes.ACC_SYNTHETIC
-                        | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
-            } else if ("RuntimeVisibleAnnotations".equals(attrName)) {
-                anns = u + 8;
-            } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
-                tanns = u + 8;
-            } else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
-                ianns = u + 8;
-            } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
-                itanns = u + 8;
-            } else {
-                Attribute attr = readAttribute(context.attrs, attrName, u + 8,
-                        readInt(u + 4), c, -1, null);
-                if (attr != null) {
-                    attr.next = attributes;
-                    attributes = attr;
-                }
-            }
-            u += 6 + readInt(u + 4);
-        }
-        u += 2;
-
-        // visits the field declaration
-        FieldVisitor fv = classVisitor.visitField(access, name, desc,
-                signature, value);
-        if (fv == null) {
-            return u;
-        }
-
-        // visits the field annotations and type annotations
-        if (anns != 0) {
-            for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
-                v = readAnnotationValues(v + 2, c, true,
-                        fv.visitAnnotation(readUTF8(v, c), true));
-            }
-        }
-        if (ianns != 0) {
-            for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
-                v = readAnnotationValues(v + 2, c, true,
-                        fv.visitAnnotation(readUTF8(v, c), false));
-            }
-        }
-        if (tanns != 0) {
-            for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
-                v = readAnnotationTarget(context, v);
-                v = readAnnotationValues(v + 2, c, true,
-                        fv.visitTypeAnnotation(context.typeRef,
-                                context.typePath, readUTF8(v, c), true));
-            }
-        }
-        if (itanns != 0) {
-            for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
-                v = readAnnotationTarget(context, v);
-                v = readAnnotationValues(v + 2, c, true,
-                        fv.visitTypeAnnotation(context.typeRef,
-                                context.typePath, readUTF8(v, c), false));
+        // Visit the RuntimeVisibleAnnotations attribute.
+        if (runtimeVisibleAnnotationsOffset != 0) {
+            int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
+            int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
+            while (numAnnotations-- > 0) {
+                // Parse the type_index field.
+                String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+                currentAnnotationOffset += 2;
+                // Parse num_element_value_pairs and element_value_pairs and visit these values.
+                currentAnnotationOffset =
+                        readElementValues(
+                                methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
+                                currentAnnotationOffset,
+                                /* named = */ true,
+                                charBuffer);
             }
         }
 
-        // visits the field attributes
-        while (attributes != null) {
-            Attribute attr = attributes.next;
-            attributes.next = null;
-            fv.visitAttribute(attributes);
-            attributes = attr;
+        // Visit the RuntimeInvisibleAnnotations attribute.
+        if (runtimeInvisibleAnnotationsOffset != 0) {
+            int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
+            int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
+            while (numAnnotations-- > 0) {
+                // Parse the type_index field.
+                String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+                currentAnnotationOffset += 2;
+                // Parse num_element_value_pairs and element_value_pairs and visit these values.
+                currentAnnotationOffset =
+                        readElementValues(
+                                methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
+                                currentAnnotationOffset,
+                                /* named = */ true,
+                                charBuffer);
+            }
         }
 
-        // visits the end of the field
-        fv.visitEnd();
+        // Visit the RuntimeVisibleTypeAnnotations attribute.
+        if (runtimeVisibleTypeAnnotationsOffset != 0) {
+            int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
+            int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
+            while (numAnnotations-- > 0) {
+                // Parse the target_type, target_info and target_path fields.
+                currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
+                // Parse the type_index field.
+                String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+                currentAnnotationOffset += 2;
+                // Parse num_element_value_pairs and element_value_pairs and visit these values.
+                currentAnnotationOffset =
+                        readElementValues(
+                                methodVisitor.visitTypeAnnotation(
+                                        context.currentTypeAnnotationTarget,
+                                        context.currentTypeAnnotationTargetPath,
+                                        annotationDescriptor,
+                                        /* visible = */ true),
+                                currentAnnotationOffset,
+                                /* named = */ true,
+                                charBuffer);
+            }
+        }
 
-        return u;
+        // Visit the RuntimeInvisibleTypeAnnotations attribute.
+        if (runtimeInvisibleTypeAnnotationsOffset != 0) {
+            int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
+            int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
+            while (numAnnotations-- > 0) {
+                // Parse the target_type, target_info and target_path fields.
+                currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
+                // Parse the type_index field.
+                String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
+                currentAnnotationOffset += 2;
+                // Parse num_element_value_pairs and element_value_pairs and visit these values.
+                currentAnnotationOffset =
+                        readElementValues(
+                                methodVisitor.visitTypeAnnotation(
+                                        context.currentTypeAnnotationTarget,
+                                        context.currentTypeAnnotationTargetPath,
+                                        annotationDescriptor,
+                                        /* visible = */ false),
+                                currentAnnotationOffset,
+                                /* named = */ true,
+                                charBuffer);
+            }
+        }
+
+        // Visit the RuntimeVisibleParameterAnnotations attribute.
+        if (runtimeVisibleParameterAnnotationsOffset != 0) {
+            readParameterAnnotations(
+                    methodVisitor, context, runtimeVisibleParameterAnnotationsOffset, /* visible = */ true);
+        }
+
+        // Visit the RuntimeInvisibleParameterAnnotations attribute.
+        if (runtimeInvisibleParameterAnnotationsOffset != 0) {
+            readParameterAnnotations(
+                    methodVisitor,
+                    context,
+                    runtimeInvisibleParameterAnnotationsOffset,
+                    /* visible = */ false);
+        }
+
+        // Visit the non standard attributes.
+        while (attributes != null) {
+            // Copy and reset the nextAttribute field so that it can also be used in MethodWriter.
+            Attribute nextAttribute = attributes.nextAttribute;
+            attributes.nextAttribute = null;
+            methodVisitor.visitAttribute(attributes);
+            attributes = nextAttribute;
+        }
+
+        // Visit the Code attribute.
+        if (codeOffset != 0) {
+            methodVisitor.visitCode();
+            readCode(methodVisitor, context, codeOffset);
+        }
+
+        // Visit the end of the method.
+        methodVisitor.visitEnd();
+        return currentOffset;
     }
 
+    // ----------------------------------------------------------------------------------------------
+    // Methods to parse a Code attribute
+    // ----------------------------------------------------------------------------------------------
+
     /**
-     * Reads a method and makes the given visitor visit it.
-     *
-     * @param classVisitor
-     *            the visitor that must visit the method.
-     * @param context
-     *            information about the class being parsed.
-     * @param u
-     *            the start offset of the method in the class file.
-     * @return the offset of the first byte following the method in the class.
-     */
-    private int readMethod(final ClassVisitor classVisitor,
-            final Context context, int u) {
-        // reads the method declaration
-        char[] c = context.buffer;
-        context.access = readUnsignedShort(u);
-        context.name = readUTF8(u + 2, c);
-        context.desc = readUTF8(u + 4, c);
-        u += 6;
+      * Reads a JVMS 'Code' attribute and makes the given visitor visit it.
+      *
+      * @param methodVisitor the visitor that must visit the Code attribute.
+      * @param context information about the class being parsed.
+      * @param codeOffset the start offset in {@link #b} of the Code attribute, excluding its
+      *     attribute_name_index and attribute_length fields.
+      */
+    private void readCode(
+            final MethodVisitor methodVisitor, final Context context, final int codeOffset) {
+        int currentOffset = codeOffset;
 
-        // reads the method attributes
-        int code = 0;
-        int exception = 0;
-        String[] exceptions = null;
-        String signature = null;
-        int methodParameters = 0;
-        int anns = 0;
-        int ianns = 0;
-        int tanns = 0;
-        int itanns = 0;
-        int dann = 0;
-        int mpanns = 0;
-        int impanns = 0;
-        int firstAttribute = u;
+        // Read the max_stack, max_locals and code_length fields.
+        final byte[] classFileBuffer = b;
+        final char[] charBuffer = context.charBuffer;
+        final int maxStack = readUnsignedShort(currentOffset);
+        final int maxLocals = readUnsignedShort(currentOffset + 2);
+        final int codeLength = readInt(currentOffset + 4);
+        currentOffset += 8;
+
+        // Read the bytecode 'code' array to create a label for each referenced instruction.
+        final int bytecodeStartOffset = currentOffset;
+        final int bytecodeEndOffset = currentOffset + codeLength;
+        final Label[] labels = context.currentMethodLabels = new Label[codeLength + 1];
+        while (currentOffset < bytecodeEndOffset) {
+            final int bytecodeOffset = currentOffset - bytecodeStartOffset;
+            final int opcode = classFileBuffer[currentOffset] & 0xFF;
+            switch (opcode) {
+                case Constants.NOP:
+                case Constants.ACONST_NULL:
+                case Constants.ICONST_M1:
+                case Constants.ICONST_0:
+                case Constants.ICONST_1:
+                case Constants.ICONST_2:
+                case Constants.ICONST_3:
+                case Constants.ICONST_4:
+                case Constants.ICONST_5:
+                case Constants.LCONST_0:
+                case Constants.LCONST_1:
+                case Constants.FCONST_0:
+                case Constants.FCONST_1:
+                case Constants.FCONST_2:
+                case Constants.DCONST_0:
+                case Constants.DCONST_1:
+                case Constants.IALOAD:
+                case Constants.LALOAD:
+                case Constants.FALOAD:
+                case Constants.DALOAD:
+                case Constants.AALOAD:
+                case Constants.BALOAD:
+                case Constants.CALOAD:
+                case Constants.SALOAD:
+                case Constants.IASTORE:
+                case Constants.LASTORE:
+                case Constants.FASTORE:
+                case Constants.DASTORE:
+                case Constants.AASTORE:
+                case Constants.BASTORE:
+                case Constants.CASTORE:
+                case Constants.SASTORE:
+                case Constants.POP:
+                case Constants.POP2:
+                case Constants.DUP:
+                case Constants.DUP_X1:
+                case Constants.DUP_X2:
+                case Constants.DUP2:
+                case Constants.DUP2_X1:
+                case Constants.DUP2_X2:
+                case Constants.SWAP:
+                case Constants.IADD:
+                case Constants.LADD:
+                case Constants.FADD:
+                case Constants.DADD:
+                case Constants.ISUB:
+                case Constants.LSUB:
+                case Constants.FSUB:
+                case Constants.DSUB:
+                case Constants.IMUL:
+                case Constants.LMUL:
+                case Constants.FMUL:
+                case Constants.DMUL:
+                case Constants.IDIV:
+                case Constants.LDIV:
+                case Constants.FDIV:
+                case Constants.DDIV:
+                case Constants.IREM:
+                case Constants.LREM:
+                case Constants.FREM:
+                case Constants.DREM:
+                case Constants.INEG:
+                case Constants.LNEG:
+                case Constants.FNEG:
+                case Constants.DNEG:
+                case Constants.ISHL:
+                case Constants.LSHL:
+                case Constants.ISHR:
+                case Constants.LSHR:
+                case Constants.IUSHR:
+                case Constants.LUSHR:
+                case Constants.IAND:
+                case Constants.LAND:
+                case Constants.IOR:
+                case Constants.LOR:
+                case Constants.IXOR:
+                case Constants.LXOR:
+                case Constants.I2L:
+                case Constants.I2F:
+                case Constants.I2D:
+                case Constants.L2I:
+                case Constants.L2F:
+                case Constants.L2D:
+                case Constants.F2I:
+                case Constants.F2L:
+                case Constants.F2D:
+                case Constants.D2I:
+                case Constants.D2L:
+                case Constants.D2F:
+                case Constants.I2B:
+                case Constants.I2C:
+                case Constants.I2S:
+                case Constants.LCMP:
+                case Constants.FCMPL:
+                case Constants.FCMPG:
+                case Constants.DCMPL:
+                case Constants.DCMPG:
+                case Constants.IRETURN:
+                case Constants.LRETURN:
+                case Constants.FRETURN:
+                case Constants.DRETURN:
+                case Constants.ARETURN:
+                case Constants.RETURN:
+                case Constants.ARRAYLENGTH:
+                case Constants.ATHROW:
+                case Constants.MONITORENTER:
+                case Constants.MONITOREXIT:
+                case Constants.ILOAD_0:
+                case Constants.ILOAD_1:
+                case Constants.ILOAD_2:
+                case Constants.ILOAD_3:
+                case Constants.LLOAD_0:
+                case Constants.LLOAD_1:
+                case Constants.LLOAD_2:
+                case Constants.LLOAD_3:
+                case Constants.FLOAD_0:
+                case Constants.FLOAD_1:
+                case Constants.FLOAD_2:
+                case Constants.FLOAD_3:
+                case Constants.DLOAD_0:
+                case Constants.DLOAD_1:
+                case Constants.DLOAD_2:
+                case Constants.DLOAD_3:
+                case Constants.ALOAD_0:
+                case Constants.ALOAD_1:
+                case Constants.ALOAD_2:
+                case Constants.ALOAD_3:
+                case Constants.ISTORE_0:
+                case Constants.ISTORE_1:
+                case Constants.ISTORE_2:
+                case Constants.ISTORE_3:
+                case Constants.LSTORE_0:
+                case Constants.LSTORE_1:
+                case Constants.LSTORE_2:
+                case Constants.LSTORE_3:
+                case Constants.FSTORE_0:
+                case Constants.FSTORE_1:
+                case Constants.FSTORE_2:
+                case Constants.FSTORE_3:
+                case Constants.DSTORE_0:
+                case Constants.DSTORE_1:
+                case Constants.DSTORE_2:
+                case Constants.DSTORE_3:
+                case Constants.ASTORE_0:
+                case Constants.ASTORE_1:
+                case Constants.ASTORE_2:
+                case Constants.ASTORE_3:
+                    currentOffset += 1;
+                    break;
+                case Constants.IFEQ:
+                case Constants.IFNE:
+                case Constants.IFLT:
+                case Constants.IFGE:
+                case Constants.IFGT:
+                case Constants.IFLE:
+                case Constants.IF_ICMPEQ:
+                case Constants.IF_ICMPNE:
+                case Constants.IF_ICMPLT:
+                case Constants.IF_ICMPGE:
+                case Constants.IF_ICMPGT:
+                case Constants.IF_ICMPLE:
+                case Constants.IF_ACMPEQ:
+                case Constants.IF_ACMPNE:
+                case Constants.GOTO:
+                case Constants.JSR:
+                case Constants.IFNULL:
+                case Constants.IFNONNULL:
+                    createLabel(bytecodeOffset + readShort(currentOffset + 1), labels);
+                    currentOffset += 3;
+                    break;
+                case Constants.ASM_IFEQ:
+                case Constants.ASM_IFNE:
+                case Constants.ASM_IFLT:
+                case Constants.ASM_IFGE:
+                case Constants.ASM_IFGT:
+                case Constants.ASM_IFLE:
+                case Constants.ASM_IF_ICMPEQ:
+                case Constants.ASM_IF_ICMPNE:
+                case Constants.ASM_IF_ICMPLT:
+                case Constants.ASM_IF_ICMPGE:
+                case Constants.ASM_IF_ICMPGT:
+                case Constants.ASM_IF_ICMPLE:
+                case Constants.ASM_IF_ACMPEQ:
+                case Constants.ASM_IF_ACMPNE:
+                case Constants.ASM_GOTO:
+                case Constants.ASM_JSR:
+                case Constants.ASM_IFNULL:
+                case Constants.ASM_IFNONNULL:
+                    createLabel(bytecodeOffset + readUnsignedShort(currentOffset + 1), labels);
+                    currentOffset += 3;
+                    break;
+                case Constants.GOTO_W:
+                case Constants.JSR_W:
+                case Constants.ASM_GOTO_W:
+                    createLabel(bytecodeOffset + readInt(currentOffset + 1), labels);
+                    currentOffset += 5;
+                    break;
+                case Constants.WIDE:
+                    switch (classFileBuffer[currentOffset + 1] & 0xFF) {
+                        case Constants.ILOAD:
+                        case Constants.FLOAD:
+                        case Constants.ALOAD:
+                        case Constants.LLOAD:
+                        case Constants.DLOAD:
+                        case Constants.ISTORE:
+                        case Constants.FSTORE:
+                        case Constants.ASTORE:
+                        case Constants.LSTORE:
+                        case Constants.DSTORE:
+                        case Constants.RET:
+                            currentOffset += 4;
+                            break;
+                        case Constants.IINC:
+                            currentOffset += 6;
+                            break;
+                        default:
+                            throw new IllegalArgumentException();
+                    }
+                    break;
+                case Constants.TABLESWITCH:
+                    // Skip 0 to 3 padding bytes.
+                    currentOffset += 4 - (bytecodeOffset & 3);
+                    // Read the default label and the number of table entries.
+                    createLabel(bytecodeOffset + readInt(currentOffset), labels);
+                    int numTableEntries = readInt(currentOffset + 8) - readInt(currentOffset + 4) + 1;
+                    currentOffset += 12;
+                    // Read the table labels.
+                    while (numTableEntries-- > 0) {
+                        createLabel(bytecodeOffset + readInt(currentOffset), labels);
+                        currentOffset += 4;
+                    }
+                    break;
+                case Constants.LOOKUPSWITCH:
+                    // Skip 0 to 3 padding bytes.
+                    currentOffset += 4 - (bytecodeOffset & 3);
+                    // Read the default label and the number of switch cases.
+                    createLabel(bytecodeOffset + readInt(currentOffset), labels);<