diff a/src/hotspot/share/cds/classListParser.cpp b/src/hotspot/share/cds/classListParser.cpp
--- a/src/hotspot/share/cds/classListParser.cpp
+++ b/src/hotspot/share/cds/classListParser.cpp
@@ -22,38 +22,49 @@
  *
  */
 
 #include "precompiled.hpp"
 #include "cds/archiveUtils.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/classListParser.hpp"
+#include "cds/classPrelinker.hpp"
 #include "cds/lambdaFormInvokers.hpp"
 #include "cds/metaspaceShared.hpp"
 #include "cds/unregisteredClasses.hpp"
-#include "classfile/classLoaderExt.hpp"
 #include "classfile/javaClasses.inline.hpp"
 #include "classfile/symbolTable.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "classfile/systemDictionaryShared.hpp"
 #include "classfile/vmClasses.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "interpreter/bytecode.hpp"
-#include "interpreter/bytecodeStream.hpp"
+#include "interpreter/interpreterRuntime.hpp"
 #include "interpreter/linkResolver.hpp"
 #include "jimage.hpp"
 #include "jvm.h"
 #include "logging/log.hpp"
 #include "logging/logTag.hpp"
+#include "memory/oopFactory.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/constantPool.inline.hpp"
+#include "oops/cpCache.inline.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/java.hpp"
 #include "runtime/javaCalls.hpp"
 #include "utilities/defaultStream.hpp"
 #include "utilities/macros.hpp"
 #include "utilities/utf8.hpp"
 
+const char* ClassListParser::CLASS_REFLECTION_DATA_TAG = "@class-reflection-data";
+const char* ClassListParser::CONSTANT_POOL_TAG = "@cp";
+const char* ClassListParser::DYNAMIC_PROXY_TAG = "@dynamic-proxy";
+const char* ClassListParser::LAMBDA_FORM_TAG = "@lambda-form-invoker";
+const char* ClassListParser::LAMBDA_PROXY_TAG = "@lambda-proxy";
+const char* ClassListParser::LOADER_NEGATIVE_CACHE_TAG = "@loader-negative-cache";
+const char* ClassListParser::ARRAY_TAG = "@array";
+
 volatile Thread* ClassListParser::_parsing_thread = nullptr;
 ClassListParser* ClassListParser::_instance = nullptr;
 
 ClassListParser::ClassListParser(const char* file, ParseMode parse_mode) :
     _classlist_file(file),
@@ -297,10 +308,25 @@
         resolve_indy(THREAD, class_name_symbol);
       }
     }
   } else if (strcmp(_token, LAMBDA_FORM_TAG) == 0) {
     LambdaFormInvokers::append(os::strdup((const char*)(_line + offset), mtInternal));
+  } else if (strcmp(_token, CONSTANT_POOL_TAG) == 0) {
+    _token = _line + offset;
+    parse_constant_pool_tag();
+  } else if (strcmp(_token, ARRAY_TAG) == 0) {
+    _token = _line + offset;
+    parse_array_dimension_tag();
+  } else if (strcmp(_token, CLASS_REFLECTION_DATA_TAG) == 0) {
+    _token = _line + offset;
+    parse_class_reflection_data_tag();
+  } else if (strcmp(_token, DYNAMIC_PROXY_TAG) == 0) {
+    _token = _line + offset;
+    parse_dynamic_proxy_tag();
+  } else if (strcmp(_token, LOADER_NEGATIVE_CACHE_TAG) == 0) {
+    _token = _line + offset;
+    parse_loader_negative_cache_tag();
   } else {
     error("Invalid @ tag at the beginning of line \"%s\" line #%zu", _token, lineno());
   }
 }
 
@@ -393,13 +419,18 @@
     jio_fprintf(defaultStream::error_stream(), "  %s\n", e->name()->as_klass_external_name());
   }
   jio_fprintf(defaultStream::error_stream(), "}\n");
 }
 
-void ClassListParser::error(const char* msg, ...) {
+void ClassListParser::print_diagnostic_info(outputStream* st, const char* msg, ...) {
   va_list ap;
   va_start(ap, msg);
+  print_diagnostic_info(st, msg, ap);
+  va_end(ap);
+}
+
+void ClassListParser::print_diagnostic_info(outputStream* st, const char* msg, va_list ap) {
   int error_index = pointer_delta_as_int(_token, _line);
   if (error_index >= _line_len) {
     error_index = _line_len - 1;
   }
   if (error_index < 0) {
@@ -410,29 +441,38 @@
               "An error has occurred while processing class list file %s %zu:%d.\n",
               _classlist_file, lineno(), (error_index + 1));
   jio_vfprintf(defaultStream::error_stream(), msg, ap);
 
   if (_line_len <= 0) {
-    jio_fprintf(defaultStream::error_stream(), "\n");
+    st->print("\n");
   } else {
-    jio_fprintf(defaultStream::error_stream(), ":\n");
+    st->print(":\n");
     for (int i=0; i<_line_len; i++) {
       char c = _line[i];
       if (c == '\0') {
-        jio_fprintf(defaultStream::error_stream(), "%s", " ");
+        st->print("%s", " ");
       } else {
-        jio_fprintf(defaultStream::error_stream(), "%c", c);
+        st->print("%c", c);
       }
     }
-    jio_fprintf(defaultStream::error_stream(), "\n");
+    st->print("\n");
     for (int i=0; i<error_index; i++) {
-      jio_fprintf(defaultStream::error_stream(), "%s", " ");
+      st->print("%s", " ");
     }
-    jio_fprintf(defaultStream::error_stream(), "^\n");
+    st->print("^\n");
   }
-  va_end(ap);
+}
 
+void ClassListParser::error(const char* msg, ...) {
+  va_list ap;
+  va_start(ap, msg);
+  fileStream fs(defaultStream::error_stream());
+  //TODO: we should write to UL/error instead, but that requires fixing some tests cases.
+  //LogTarget(Error, cds) lt;
+  //LogStream ls(lt);
+  print_diagnostic_info(&fs, msg, ap);
+  va_end(ap);
   vm_exit_during_initialization("class list format error.", nullptr);
 }
 
 void ClassListParser::check_class_name(const char* class_name) {
   const char* err = nullptr;
@@ -451,10 +491,20 @@
               _classlist_file, lineno(), err);
     vm_exit_during_initialization("class list format error.", nullptr);
   }
 }
 
+void ClassListParser::constant_pool_resolution_warning(const char* msg, ...) {
+  va_list ap;
+  va_start(ap, msg);
+  LogTarget(Warning, cds, resolve) lt;
+  LogStream ls(lt);
+  print_diagnostic_info(&ls, msg, ap);
+  ls.print("Your classlist may be out of sync with the JDK or the application.");
+  va_end(ap);
+}
+
 // This function is used for loading classes for customized class loaders
 // during archive dumping.
 InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS) {
 #if !(defined(_LP64) && (defined(LINUX) || defined(__APPLE__) || defined(_WINDOWS)))
   // The only supported platforms are: (1) Linux/64-bit and (2) Solaris/64-bit and
@@ -725,5 +775,307 @@
   error("The interface %s implemented by class %s does not match any of the specified interface IDs",
         interface_name->as_klass_external_name(), _class_name);
   ShouldNotReachHere();
   return nullptr;
 }
+
+InstanceKlass* ClassListParser::find_builtin_class_helper(JavaThread* current, Symbol* class_name_symbol, oop class_loader_oop) {
+  Handle class_loader(current, class_loader_oop);
+  Handle protection_domain;
+  return SystemDictionary::find_instance_klass(current, class_name_symbol, class_loader, protection_domain);
+}
+
+InstanceKlass* ClassListParser::find_builtin_class(JavaThread* current, const char* class_name) {
+  TempNewSymbol class_name_symbol = SymbolTable::new_symbol(class_name);
+  InstanceKlass* ik;
+
+  if ( (ik = find_builtin_class_helper(current, class_name_symbol, nullptr)) != nullptr
+    || (ik = find_builtin_class_helper(current, class_name_symbol, SystemDictionary::java_platform_loader())) != nullptr
+    || (ik = find_builtin_class_helper(current, class_name_symbol, SystemDictionary::java_system_loader())) != nullptr) {
+    return ik;
+  } else {
+    return nullptr;
+  }
+}
+
+void ClassListParser::parse_array_dimension_tag() {
+  if (parse_lambda_forms_invokers_only()) {
+    return;
+  }
+
+  skip_whitespaces();
+  char* class_name = _token;
+  skip_non_whitespaces();
+  *_token = '\0';
+  _token ++;
+
+  skip_whitespaces();
+  int dim;
+  parse_uint(&dim);
+
+  JavaThread* THREAD = JavaThread::current();
+  InstanceKlass* ik = find_builtin_class(THREAD, class_name);
+  if (ik == nullptr) {
+    _token = class_name;
+    if (strstr(class_name, "/$Proxy") != nullptr ||
+        strstr(class_name, "MethodHandle$Species_") != nullptr) {
+      // ignore -- TODO: we should filter these out in classListWriter.cpp
+    } else {
+      constant_pool_resolution_warning("class %s is not (yet) loaded by one of the built-in loaders", class_name);
+    }
+    return;
+  }
+
+  if (dim > 0) {
+    ik->array_klass(dim, THREAD);
+    if (HAS_PENDING_EXCEPTION) {
+      error("Array klass allocation failed: %s %d", _class_name, dim);
+    }
+  }
+}
+
+void ClassListParser::parse_constant_pool_tag() {
+  if (parse_lambda_forms_invokers_only()) {
+    return;
+  }
+
+  JavaThread* THREAD = JavaThread::current();
+  skip_whitespaces();
+  char* class_name = _token;
+  skip_non_whitespaces();
+  *_token = '\0';
+  _token ++;
+
+  InstanceKlass* ik = find_builtin_class(THREAD, class_name);
+  if (ik == nullptr) {
+    _token = class_name;
+    if (strstr(class_name, "/$Proxy") != nullptr ||
+        strstr(class_name, "MethodHandle$Species_") != nullptr) {
+      // ignore -- TODO: we should filter these out in classListWriter.cpp
+    } else {
+      constant_pool_resolution_warning("class %s is not (yet) loaded by one of the built-in loaders", class_name);
+    }
+    return;
+  }
+
+  ResourceMark rm(THREAD);
+  constantPoolHandle cp(THREAD, ik->constants());
+  GrowableArray<bool> preresolve_list(cp->length(), cp->length(), false);
+  bool preresolve_class = false;
+  bool preresolve_fmi = false;
+  bool preresolve_indy = false;
+  
+  while (*_token) {
+    int cp_index;
+    skip_whitespaces();
+    parse_uint(&cp_index);
+    if (cp_index < 1 || cp_index >= cp->length()) {
+      constant_pool_resolution_warning("Invalid constant pool index %d", cp_index);
+      return;
+    } else {
+      preresolve_list.at_put(cp_index, true);
+    }
+    constantTag cp_tag = cp->tag_at(cp_index);
+    switch (cp_tag.value()) {
+    case JVM_CONSTANT_UnresolvedClass:
+      preresolve_class = true;
+      break;
+    case JVM_CONSTANT_UnresolvedClassInError:
+    case JVM_CONSTANT_Class:
+      // ignore
+      break;
+    case JVM_CONSTANT_Fieldref:
+    case JVM_CONSTANT_Methodref:
+    case JVM_CONSTANT_InterfaceMethodref:
+      preresolve_fmi = true;
+      break;
+    case JVM_CONSTANT_InvokeDynamic:
+      preresolve_indy = true;
+      break;
+    default:
+      constant_pool_resolution_warning("Unsupported constant pool index %d: %s (type=%d)",
+                                       cp_index, cp_tag.internal_name(), cp_tag.value());
+      return;
+    }
+  }
+
+  if (preresolve_class) {
+    ClassPrelinker::preresolve_class_cp_entries(THREAD, ik, &preresolve_list);
+  }
+  if (preresolve_fmi) {
+// FIXME: too coarse; doesn't cover resolution of Class entries
+//    JavaThread::NoJavaCodeMark no_java_code(THREAD); // ensure no clinits are exectued
+    ClassPrelinker::preresolve_field_and_method_cp_entries(THREAD, ik, &preresolve_list);
+  }
+  if (preresolve_indy) {
+    ClassPrelinker::preresolve_indy_cp_entries(THREAD, ik, &preresolve_list);
+  }
+}
+
+void ClassListParser::parse_class_reflection_data_tag() {
+  if (parse_lambda_forms_invokers_only()) {
+    return;
+  }
+
+  JavaThread* THREAD = JavaThread::current();
+  skip_whitespaces();
+  char* class_name = _token;
+  skip_non_whitespaces();
+  *_token = '\0';
+  _token ++;
+
+  InstanceKlass* ik = find_builtin_class(THREAD, class_name);
+  if (ik == nullptr) {
+    _token = class_name;
+    if (strstr(class_name, "/$Proxy") != nullptr ||
+        strstr(class_name, "MethodHandle$Species_") != nullptr) {
+      // ignore -- TODO: we should filter these out in classListWriter.cpp
+    } else {
+      warning("%s: class not found: %s", CLASS_REFLECTION_DATA_TAG, class_name);
+    }
+    return;
+  }
+
+  ResourceMark rm(THREAD);
+
+  int rd_flags = _unspecified;
+  while (*_token) {
+    skip_whitespaces();
+    if (rd_flags != _unspecified) {
+      error("rd_flags specified twice");
+      return;
+    }
+    parse_uint(&rd_flags);
+  }
+  if (rd_flags == _unspecified) {
+    error("no rd_flags specified");
+    return;
+  }
+
+  if (ArchiveReflectionData) {
+    ClassPrelinker::generate_reflection_data(THREAD, ik, rd_flags);
+  }
+}
+
+oop ClassListParser::loader_from_type(const char* loader_type) {
+  oop loader;
+  if (!ArchiveUtils::builtin_loader_from_type(loader_type, &loader)) {
+    error("Unknown loader %s", loader_type);
+  }
+  return loader;
+}
+
+void ClassListParser::parse_dynamic_proxy_tag() {
+  if (parse_lambda_forms_invokers_only()) {
+    return;
+  }
+
+  skip_whitespaces();
+  char* loader_type = _token;
+  skip_non_whitespaces();
+  *_token = '\0';
+  _token ++;
+
+  skip_whitespaces();
+  char* proxy_name_str = _token;
+  skip_non_whitespaces();
+  *_token = '\0';
+  _token ++;
+
+  skip_whitespaces();
+  int access_flags;
+  parse_uint(&access_flags);
+
+  skip_whitespaces();
+  int num_intfs;
+  parse_uint(&num_intfs);
+
+  JavaThread* THREAD = JavaThread::current();
+  Handle loader(THREAD, loader_from_type(loader_type));
+  Handle proxy_name(THREAD, java_lang_String::create_oop_from_str(proxy_name_str, THREAD));
+  if (HAS_PENDING_EXCEPTION) {
+    error("Out of memory");
+  }
+
+  objArrayHandle interfaces(THREAD, oopFactory::new_objArray(vmClasses::Class_klass(), num_intfs, THREAD));
+  if (HAS_PENDING_EXCEPTION) {
+    error("Out of memory");
+  }
+
+  for (int i = 0; i < num_intfs; i++) {
+    skip_whitespaces();
+    char* intf_name = _token;
+    skip_non_whitespaces();
+    *_token = '\0';
+    _token ++;
+
+    InstanceKlass* ik = find_builtin_class(THREAD, intf_name);
+    if (ik != nullptr) {
+      interfaces()->obj_at_put(i, ik->java_mirror());
+    } else {
+      error("Unknown class %s", intf_name);
+    }
+  }
+
+  if (strncmp("jdk.proxy", proxy_name_str, 9) != 0) {
+    return;
+  }
+
+  ClassPrelinker::define_dynamic_proxy_class(loader, proxy_name, interfaces, access_flags, THREAD);
+  if (HAS_PENDING_EXCEPTION) {
+    PENDING_EXCEPTION->print_on(tty);
+    error("defineProxyClassForCDS failed");
+  }
+}
+
+void ClassListParser::parse_loader_negative_cache_tag() {
+  skip_whitespaces();
+  char* loader_type = _token;
+  skip_non_whitespaces();
+  *_token = '\0';
+  _token ++;
+
+  oop loader;
+  Klass* loader_klass;
+  if (!strcmp(loader_type, "app")) {
+    loader = SystemDictionary::java_system_loader();
+    loader_klass = vmClasses::jdk_internal_loader_ClassLoaders_AppClassLoader_klass();
+  } else if (!strcmp(loader_type, "platform")) {
+    loader = SystemDictionary::java_platform_loader();
+    loader_klass = vmClasses::jdk_internal_loader_ClassLoaders_PlatformClassLoader_klass();
+  } else {
+    warning("%s: unrecognized loader type %s is ignored", LOADER_NEGATIVE_CACHE_TAG, loader_type);
+    return;
+  }
+
+  char* contents = _token;
+  skip_non_whitespaces();
+  *_token = '\0';
+  _token ++;
+
+  if (ArchiveLoaderLookupCache) {
+    TempNewSymbol method = SymbolTable::new_symbol("generateNegativeLookupCache");
+    TempNewSymbol signature = SymbolTable::new_symbol("(Ljava/lang/String;)V");
+
+    EXCEPTION_MARK;
+    HandleMark hm(THREAD);
+    JavaCallArguments args(Handle(THREAD, loader));
+    Handle contents_h = java_lang_String::create_from_str(contents, THREAD);
+    args.push_oop(contents_h);
+    JavaValue result(T_VOID);
+    JavaCalls::call_virtual(&result,
+                            loader_klass,
+                            method,
+                            signature,
+                            &args, THREAD);
+    if (HAS_PENDING_EXCEPTION) {
+      Handle exc_handle(THREAD, PENDING_EXCEPTION);
+      CLEAR_PENDING_EXCEPTION;
+
+      log_warning(cds)("Exception during BuiltinClassLoader::generateNegativeLookupCache() call for %s loader", loader_type);
+      LogStreamHandle(Debug, cds) log;
+      if (log.is_enabled()) {
+        java_lang_Throwable::print_stack_trace(exc_handle, &log);
+      }
+    }
+  }
+}
