merge JDK-8200758-branch
authorherrick
Tue, 19 Nov 2019 18:45:08 -0500
branchJDK-8200758-branch
changeset 59159 d1fe86ccc832
parent 59127 4ad81e9e30fd (current diff)
parent 59140 f68fd04fe463 (diff)
child 59160 e90068e7afa1
merge
test/jdk/jdk/modules/etc/src/TestJson.java
test/jdk/jdk/modules/etc/src/TestRootModules.java
--- a/make/lib/Awt2dLibraries.gmk	Mon Nov 18 12:40:06 2019 -0500
+++ b/make/lib/Awt2dLibraries.gmk	Tue Nov 19 18:45:08 2019 -0500
@@ -383,7 +383,7 @@
         libawt/java2d, \
     HEADERS_FROM_SRC := $(LIBLCMS_HEADERS_FROM_SRC), \
     DISABLED_WARNINGS_gcc := format-nonliteral type-limits \
-        misleading-indentation undef unused-function, \
+        misleading-indentation undef unused-function stringop-truncation, \
     DISABLED_WARNINGS_clang := tautological-compare format-nonliteral undef, \
     DISABLED_WARNINGS_solstudio := E_STATEMENT_NOT_REACHED, \
     DISABLED_WARNINGS_microsoft := 4819, \
--- a/src/hotspot/share/classfile/defaultMethods.cpp	Mon Nov 18 12:40:06 2019 -0500
+++ b/src/hotspot/share/classfile/defaultMethods.cpp	Tue Nov 19 18:45:08 2019 -0500
@@ -47,38 +47,6 @@
 
 typedef enum { QUALIFIED, DISQUALIFIED } QualifiedState;
 
-// Because we use an iterative algorithm when iterating over the type
-// hierarchy, we can't use traditional scoped objects which automatically do
-// cleanup in the destructor when the scope is exited.  PseudoScope (and
-// PseudoScopeMark) provides a similar functionality, but for when you want a
-// scoped object in non-stack memory (such as in resource memory, as we do
-// here).  You've just got to remember to call 'destroy()' on the scope when
-// leaving it (and marks have to be explicitly added).
-class PseudoScopeMark : public ResourceObj {
- public:
-  virtual void destroy() = 0;
-};
-
-class PseudoScope : public ResourceObj {
- private:
-  GrowableArray<PseudoScopeMark*> _marks;
- public:
-
-  static PseudoScope* cast(void* data) {
-    return static_cast<PseudoScope*>(data);
-  }
-
-  void add_mark(PseudoScopeMark* psm) {
-   _marks.append(psm);
-  }
-
-  void destroy() {
-    for (int i = 0; i < _marks.length(); ++i) {
-      _marks.at(i)->destroy();
-    }
-  }
-};
-
 static void print_slot(outputStream* str, Symbol* name, Symbol* signature) {
   str->print("%s%s", name->as_C_string(), signature->as_C_string());
 }
@@ -108,13 +76,13 @@
  *
  * The ALGO class, must provide a visit() method, which each of which will be
  * called once for each node in the inheritance tree during the iteration.  In
- * addition, it can provide a memory block via new_node_data(InstanceKlass*),
- * which it can use for node-specific storage (and access via the
- * current_data() and data_at_depth(int) methods).
+ * addition, it can provide a memory block via new_node_data(), which it can
+ * use for node-specific storage (and access via the current_data() and
+ * data_at_depth(int) methods).
  *
  * Bare minimum needed to be an ALGO class:
  * class Algo : public HierarchyVisitor<Algo> {
- *   void* new_node_data(InstanceKlass* cls) { return NULL; }
+ *   void* new_node_data() { return NULL; }
  *   void free_node_data(void* data) { return; }
  *   bool visit() { return true; }
  * };
@@ -134,6 +102,12 @@
         : _class(cls), _super_was_visited(!visit_super),
           _interface_index(0), _algorithm_data(data) {}
 
+    void update(InstanceKlass* cls, void* data, bool visit_super) {
+      _class = cls;
+      _super_was_visited = !visit_super;
+      _interface_index = 0;
+      _algorithm_data = data;
+    }
     int number_of_interfaces() { return _class->local_interfaces()->length(); }
     int interface_index() { return _interface_index; }
     void set_super_visited() { _super_was_visited = true; }
@@ -155,19 +129,32 @@
   };
 
   bool _visited_Object;
+
   GrowableArray<Node*> _path;
+  GrowableArray<Node*> _free_nodes;
 
   Node* current_top() const { return _path.top(); }
-  bool has_more_nodes() const { return !_path.is_empty(); }
-  void push(InstanceKlass* cls, void* data) {
+  bool has_more_nodes() const { return _path.length() > 0; }
+  void push(InstanceKlass* cls, ALGO* algo) {
     assert(cls != NULL, "Requires a valid instance class");
-    Node* node = new Node(cls, data, has_super(cls));
     if (cls == SystemDictionary::Object_klass()) {
       _visited_Object = true;
     }
+    void* data = algo->new_node_data();
+    Node* node;
+    if (_free_nodes.is_empty()) { // Add a new node
+      node = new Node(cls, data, has_super(cls));
+    } else { // Reuse existing node and data
+      node = _free_nodes.pop();
+      node->update(cls, data, has_super(cls));
+    }
     _path.push(node);
   }
-  void pop() { _path.pop(); }
+  void pop() {
+    Node* node = _path.pop();
+    // Make the node available for reuse
+    _free_nodes.push(node);
+  }
 
   // Since the starting point can be an interface, we must ensure we catch
   // j.l.Object as the super once in those cases. The _visited_Object flag
@@ -183,6 +170,11 @@
 
  protected:
 
+  // Resets the visitor
+  void reset() {
+    _visited_Object = false;
+  }
+
   // Accessors available to the algorithm
   int current_depth() const { return _path.length() - 1; }
 
@@ -199,14 +191,13 @@
   void* current_data() { return data_at_depth(0); }
 
  public:
+  HierarchyVisitor() : _visited_Object(false), _path() {}
 
   void run(InstanceKlass* root) {
     ALGO* algo = static_cast<ALGO*>(this);
 
-    void* algo_data = algo->new_node_data(root);
-    push(root, algo_data);
+    push(root, algo);
     bool top_needs_visit = true;
-
     do {
       Node* top = current_top();
       if (top_needs_visit) {
@@ -232,8 +223,7 @@
           top->increment_visited_interface();
         }
         assert(next != NULL, "Otherwise we shouldn't be here");
-        algo_data = algo->new_node_data(next);
-        push(next, algo_data);
+        push(next, algo);
         top_needs_visit = true;
       }
     } while (has_more_nodes());
@@ -251,7 +241,7 @@
     return true;
   }
 
-  void* new_node_data(InstanceKlass* cls) { return NULL; }
+  void* new_node_data() { return NULL; }
   void free_node_data(void* data) { return; }
 
   PrintHierarchy(outputStream* st = tty) : _st(st) {}
@@ -270,7 +260,7 @@
   GrowableArray<ConstantPool*> _keep_alive;
 
  public:
-  KeepAliveRegistrar(Thread* thread) : _thread(thread), _keep_alive(20) {
+  KeepAliveRegistrar(Thread* thread) : _thread(thread), _keep_alive(6) {
     assert(thread == Thread::current(), "Must be current thread");
   }
 
@@ -299,7 +289,7 @@
  public:
   KeepAliveVisitor(KeepAliveRegistrar* registrar) : _registrar(registrar) {}
 
-  void* new_node_data(InstanceKlass* cls) { return NULL; }
+  void* new_node_data() { return NULL; }
   void free_node_data(void* data) { return; }
 
   bool visit() {
@@ -316,36 +306,41 @@
 // from the root of hierarchy to the method that contains an interleaving
 // erased method defined in an interface.
 
+class MethodState {
+ public:
+  Method* _method;
+  QualifiedState _state;
+
+  MethodState() : _method(NULL), _state(DISQUALIFIED) {}
+  MethodState(Method* method, QualifiedState state) : _method(method), _state(state) {}
+};
+
 class MethodFamily : public ResourceObj {
  private:
 
-  GrowableArray<Pair<Method*,QualifiedState> > _members;
-  ResourceHashtable<Method*, int> _member_index;
+  GrowableArray<MethodState> _members;
 
   Method* _selected_target;  // Filled in later, if a unique target exists
   Symbol* _exception_message; // If no unique target is found
   Symbol* _exception_name;    // If no unique target is found
 
-  bool contains_method(Method* method) {
-    int* lookup = _member_index.get(method);
-    return lookup != NULL;
+  MethodState* find_method(Method* method) {
+    for (int i = 0; i < _members.length(); i++) {
+      if (_members.at(i)._method == method) {
+        return &_members.at(i);
+      }
+    }
+    return NULL;
   }
 
   void add_method(Method* method, QualifiedState state) {
-    Pair<Method*,QualifiedState> entry(method, state);
-    _member_index.put(method, _members.length());
-    _members.append(entry);
-  }
-
-  void disqualify_method(Method* method) {
-    int* index = _member_index.get(method);
-    guarantee(index != NULL && *index >= 0 && *index < _members.length(), "bad index");
-    _members.at(*index).second = DISQUALIFIED;
+    MethodState method_state(method, state);
+    _members.append(method_state);
   }
 
   Symbol* generate_no_defaults_message(TRAPS) const;
   Symbol* generate_method_message(Symbol *klass_name, Method* method, TRAPS) const;
-  Symbol* generate_conflicts_message(GrowableArray<Method*>* methods, TRAPS) const;
+  Symbol* generate_conflicts_message(GrowableArray<MethodState>* methods, TRAPS) const;
 
  public:
 
@@ -358,23 +353,15 @@
     }
   }
 
-  void record_qualified_method(Method* m) {
-    // If the method already exists in the set as qualified, this operation is
-    // redundant.  If it already exists as disqualified, then we leave it as
-    // disqualfied.  Thus we only add to the set if it's not already in the
-    // set.
-    if (!contains_method(m)) {
-      add_method(m, QUALIFIED);
-    }
-  }
-
-  void record_disqualified_method(Method* m) {
-    // If not in the set, add it as disqualified.  If it's already in the set,
-    // then set the state to disqualified no matter what the previous state was.
-    if (!contains_method(m)) {
-      add_method(m, DISQUALIFIED);
-    } else {
-      disqualify_method(m);
+  void record_method(Method* m, QualifiedState state) {
+    // If not in the set, add it.  If it's already in the set, then leave it
+    // as is if state is qualified, or set it to disqualified if state is
+    // disqualified.
+    MethodState* method_state = find_method(m);
+    if (method_state == NULL) {
+      add_method(m, state);
+    } else if (state == DISQUALIFIED) {
+      method_state->_state = DISQUALIFIED;
     }
   }
 
@@ -386,30 +373,43 @@
   Symbol* get_exception_name() { return _exception_name; }
 
   // Either sets the target or the exception error message
-  void determine_target(InstanceKlass* root, TRAPS) {
+  void determine_target_or_set_exception_message(InstanceKlass* root, TRAPS) {
     if (has_target() || throws_exception()) {
       return;
     }
 
     // Qualified methods are maximally-specific methods
     // These include public, instance concrete (=default) and abstract methods
-    GrowableArray<Method*> qualified_methods;
     int num_defaults = 0;
     int default_index = -1;
-    int qualified_index = -1;
-    for (int i = 0; i < _members.length(); ++i) {
-      Pair<Method*,QualifiedState> entry = _members.at(i);
-      if (entry.second == QUALIFIED) {
-        qualified_methods.append(entry.first);
-        qualified_index++;
-        if (entry.first->is_default_method()) {
+    for (int i = 0; i < _members.length(); i++) {
+      MethodState &member = _members.at(i);
+      if (member._state == QUALIFIED) {
+        if (member._method->is_default_method()) {
           num_defaults++;
-          default_index = qualified_index;
-
+          default_index = i;
         }
       }
     }
 
+    if (num_defaults == 1) {
+      assert(_members.at(default_index)._state == QUALIFIED, "");
+      _selected_target = _members.at(default_index)._method;
+    } else {
+      generate_and_set_exception_message(root, num_defaults, default_index, CHECK);
+    }
+  }
+
+  void generate_and_set_exception_message(InstanceKlass* root, int num_defaults, int default_index, TRAPS) {
+    assert(num_defaults != 1, "invariant - should've been handled calling method");
+
+    GrowableArray<Method*> qualified_methods;
+    for (int i = 0; i < _members.length(); i++) {
+      MethodState& member = _members.at(i);
+      if (member._state == QUALIFIED) {
+        qualified_methods.push(member._method);
+      }
+    }
     if (num_defaults == 0) {
       // If the root klass has a static method with matching name and signature
       // then do not generate an overpass method because it will hide the
@@ -421,13 +421,8 @@
         _exception_message = generate_method_message(root->name(), qualified_methods.at(0), CHECK);
       }
       _exception_name = vmSymbols::java_lang_AbstractMethodError();
-
-    // If only one qualified method is default, select that
-    } else if (num_defaults == 1) {
-        _selected_target = qualified_methods.at(default_index);
-
-    } else if (num_defaults > 1) {
-      _exception_message = generate_conflicts_message(&qualified_methods,CHECK);
+    } else {
+      _exception_message = generate_conflicts_message(&_members,CHECK);
       _exception_name = vmSymbols::java_lang_IncompatibleClassChangeError();
       LogTarget(Debug, defaultmethods) lt;
       if (lt.is_enabled()) {
@@ -475,23 +470,23 @@
   return SymbolTable::new_symbol(ss.base(), (int)ss.size());
 }
 
-Symbol* MethodFamily::generate_conflicts_message(GrowableArray<Method*>* methods, TRAPS) const {
+Symbol* MethodFamily::generate_conflicts_message(GrowableArray<MethodState>* methods, TRAPS) const {
   stringStream ss;
   ss.print("Conflicting default methods:");
   for (int i = 0; i < methods->length(); ++i) {
-    Method* method = methods->at(i);
-    Symbol* klass = method->klass_name();
-    Symbol* name = method->name();
+    Method *method = methods->at(i)._method;
+    Symbol *klass = method->klass_name();
+    Symbol *name = method->name();
     ss.print(" ");
-    ss.write((const char*)klass->bytes(), klass->utf8_length());
+    ss.write((const char*) klass->bytes(), klass->utf8_length());
     ss.print(".");
-    ss.write((const char*)name->bytes(), name->utf8_length());
+    ss.write((const char*) name->bytes(), name->utf8_length());
   }
   return SymbolTable::new_symbol(ss.base(), (int)ss.size());
 }
 
 
-class StateRestorer;
+class StateRestorerScope;
 
 // StatefulMethodFamily is a wrapper around a MethodFamily that maintains the
 // qualification state during hierarchy visitation, and applies that state
@@ -517,32 +512,72 @@
 
   MethodFamily* get_method_family() { return &_method_family; }
 
-  StateRestorer* record_method_and_dq_further(Method* mo);
+  void record_method_and_dq_further(StateRestorerScope* scope, Method* mo);
 };
 
-class StateRestorer : public PseudoScopeMark {
- private:
+// Because we use an iterative algorithm when iterating over the type
+// hierarchy, we can't use traditional scoped objects which automatically do
+// cleanup in the destructor when the scope is exited.  StateRestorerScope (and
+// StateRestorer) provides a similar functionality, but for when you want a
+// scoped object in non-stack memory (such as in resource memory, as we do
+// here).  You've just got to remember to call 'restore_state()' on the scope when
+// leaving it (and marks have to be explicitly added). The scope is reusable after
+// 'restore_state()' has been called.
+class StateRestorer : public ResourceObj {
+ public:
   StatefulMethodFamily* _method;
   QualifiedState _state_to_restore;
- public:
-  StateRestorer(StatefulMethodFamily* dm, QualifiedState state)
-      : _method(dm), _state_to_restore(state) {}
-  ~StateRestorer() { destroy(); }
+
+  StateRestorer() : _method(NULL), _state_to_restore(DISQUALIFIED) {}
+
   void restore_state() { _method->set_qualification_state(_state_to_restore); }
-  virtual void destroy() { restore_state(); }
 };
 
-StateRestorer* StatefulMethodFamily::record_method_and_dq_further(Method* mo) {
-  StateRestorer* mark = new StateRestorer(this, _qualification_state);
-  if (_qualification_state == QUALIFIED) {
-    _method_family.record_qualified_method(mo);
-  } else {
-    _method_family.record_disqualified_method(mo);
+class StateRestorerScope : public ResourceObj {
+ private:
+  GrowableArray<StateRestorer*>  _marks;
+  GrowableArray<StateRestorer*>* _free_list; // Shared between scopes
+ public:
+  StateRestorerScope(GrowableArray<StateRestorer*>* free_list) : _marks(), _free_list(free_list) {}
+
+  static StateRestorerScope* cast(void* data) {
+    return static_cast<StateRestorerScope*>(data);
   }
+
+  void mark(StatefulMethodFamily* family, QualifiedState qualification_state) {
+    StateRestorer* restorer;
+    if (!_free_list->is_empty()) {
+      restorer = _free_list->pop();
+    } else {
+      restorer = new StateRestorer();
+    }
+    restorer->_method = family;
+    restorer->_state_to_restore = qualification_state;
+    _marks.append(restorer);
+  }
+
+#ifdef ASSERT
+  bool is_empty() {
+    return _marks.is_empty();
+  }
+#endif
+
+  void restore_state() {
+    while(!_marks.is_empty()) {
+      StateRestorer* restorer = _marks.pop();
+      restorer->restore_state();
+      _free_list->push(restorer);
+    }
+  }
+};
+
+void StatefulMethodFamily::record_method_and_dq_further(StateRestorerScope* scope, Method* mo) {
+  scope->mark(this, _qualification_state);
+  _method_family.record_method(mo, _qualification_state);
+
   // Everything found "above"??? this method in the hierarchy walk is set to
   // disqualified
   set_qualification_state(DISQUALIFIED);
-  return mark;
 }
 
 // Represents a location corresponding to a vtable slot for methods that
@@ -660,11 +695,19 @@
   Symbol* _method_signature;
   StatefulMethodFamily*  _family;
   bool _cur_class_is_interface;
-
+  // Free lists, used as an optimization
+  GrowableArray<StateRestorerScope*> _free_scopes;
+  GrowableArray<StateRestorer*> _free_restorers;
  public:
-  FindMethodsByErasedSig(Symbol* name, Symbol* signature, bool is_interf) :
-      _method_name(name), _method_signature(signature), _family(NULL),
-      _cur_class_is_interface(is_interf) {}
+  FindMethodsByErasedSig() : _free_scopes(6), _free_restorers(6) {};
+
+  void prepare(Symbol* name, Symbol* signature, bool is_interf) {
+    reset();
+    _method_name = name;
+    _method_signature = signature;
+    _family = NULL;
+    _cur_class_is_interface = is_interf;
+  }
 
   void get_discovered_family(MethodFamily** family) {
       if (_family != NULL) {
@@ -674,15 +717,25 @@
       }
   }
 
-  void* new_node_data(InstanceKlass* cls) { return new PseudoScope(); }
+  void* new_node_data() {
+    if (!_free_scopes.is_empty()) {
+      StateRestorerScope* free_scope = _free_scopes.pop();
+      assert(free_scope->is_empty(), "StateRestorerScope::_marks array not empty");
+      return free_scope;
+    }
+    return new StateRestorerScope(&_free_restorers);
+  }
   void free_node_data(void* node_data) {
-    PseudoScope::cast(node_data)->destroy();
+    StateRestorerScope* scope =  StateRestorerScope::cast(node_data);
+    scope->restore_state();
+    // Reuse scopes
+    _free_scopes.push(scope);
   }
 
   // Find all methods on this hierarchy that match this
   // method's erased (name, signature)
   bool visit() {
-    PseudoScope* scope = PseudoScope::cast(current_data());
+    StateRestorerScope* scope = StateRestorerScope::cast(current_data());
     InstanceKlass* iklass = current_class();
 
     Method* m = iklass->find_method(_method_name, _method_signature);
@@ -702,8 +755,7 @@
       }
 
       if (iklass->is_interface()) {
-        StateRestorer* restorer = _family->record_method_and_dq_further(m);
-        scope->add_mark(restorer);
+        _family->record_method_and_dq_further(scope, m);
       } else {
         // This is the rule that methods in classes "win" (bad word) over
         // methods in interfaces. This works because of single inheritance.
@@ -724,16 +776,20 @@
     GrowableArray<EmptyVtableSlot*>* slots, InstanceKlass* klass, TRAPS);
 
 static void generate_erased_defaults(
-     InstanceKlass* klass, EmptyVtableSlot* slot, bool is_intf, TRAPS) {
+    FindMethodsByErasedSig* visitor,
+    InstanceKlass* klass, EmptyVtableSlot* slot, bool is_intf, TRAPS) {
 
+  // the visitor needs to be initialized or re-initialized before use
+  // - this facilitates reusing the same visitor instance on multiple
+  // generation passes as an optimization
+  visitor->prepare(slot->name(), slot->signature(), is_intf);
   // sets up a set of methods with the same exact erased signature
-  FindMethodsByErasedSig visitor(slot->name(), slot->signature(), is_intf);
-  visitor.run(klass);
+  visitor->run(klass);
 
   MethodFamily* family;
-  visitor.get_discovered_family(&family);
+  visitor->get_discovered_family(&family);
   if (family != NULL) {
-    family->determine_target(klass, CHECK);
+    family->determine_target_or_set_exception_message(klass, CHECK);
     slot->bind_family(family);
   }
 }
@@ -788,6 +844,7 @@
   find_empty_vtable_slots(&empty_slots, klass, mirandas, CHECK);
 
   if (empty_slots.length() > 0) {
+    FindMethodsByErasedSig findMethodsByErasedSig;
     for (int i = 0; i < empty_slots.length(); ++i) {
       EmptyVtableSlot* slot = empty_slots.at(i);
       LogTarget(Debug, defaultmethods) lt;
@@ -798,7 +855,7 @@
         slot->print_on(&ls);
         ls.cr();
       }
-      generate_erased_defaults(klass, slot, klass->is_interface(), CHECK);
+      generate_erased_defaults(&findMethodsByErasedSig, klass, slot, klass->is_interface(), CHECK);
     }
     log_debug(defaultmethods)("Creating defaults and overpasses...");
     create_defaults_and_exceptions(&empty_slots, klass, CHECK);
@@ -898,12 +955,12 @@
   GrowableArray<Method*> defaults;
   BytecodeConstantPool bpool(klass->constants());
 
+  BytecodeBuffer* buffer = NULL; // Lazily create a reusable buffer
   for (int i = 0; i < slots->length(); ++i) {
     EmptyVtableSlot* slot = slots->at(i);
 
     if (slot->is_bound()) {
       MethodFamily* method = slot->get_binding();
-      BytecodeBuffer buffer;
 
       LogTarget(Debug, defaultmethods) lt;
       if (lt.is_enabled()) {
@@ -926,11 +983,16 @@
           defaults.push(selected);
         }
       } else if (method->throws_exception()) {
-        int max_stack = assemble_method_error(&bpool, &buffer,
+        if (buffer == NULL) {
+          buffer = new BytecodeBuffer();
+        } else {
+          buffer->clear();
+        }
+        int max_stack = assemble_method_error(&bpool, buffer,
            method->get_exception_name(), method->get_exception_message(), CHECK);
         AccessFlags flags = accessFlags_from(
           JVM_ACC_PUBLIC | JVM_ACC_SYNTHETIC | JVM_ACC_BRIDGE);
-         Method* m = new_method(&bpool, &buffer, slot->name(), slot->signature(),
+        Method* m = new_method(&bpool, buffer, slot->name(), slot->signature(),
           flags, max_stack, slot->size_of_parameters(),
           ConstMethod::OVERPASS, CHECK);
         // We push to the methods list:
--- a/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp	Mon Nov 18 12:40:06 2019 -0500
+++ b/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp	Tue Nov 19 18:45:08 2019 -0500
@@ -279,7 +279,7 @@
   if (pretouch_gang != NULL) {
     size_t num_chunks = MAX2((size_t)1, size_in_pages * _page_size / MAX2(G1PretouchTask::chunk_size(), _page_size));
 
-    uint num_workers = MIN2((uint)num_chunks, pretouch_gang->active_workers());
+    uint num_workers = MIN2((uint)num_chunks, pretouch_gang->total_workers());
     log_debug(gc, heap)("Running %s with %u workers for " SIZE_FORMAT " work units pre-touching " SIZE_FORMAT "B.",
                         cl.name(), num_workers, num_chunks, size_in_pages * _page_size);
     pretouch_gang->run_task(&cl, num_workers);
--- a/src/hotspot/share/memory/filemap.cpp	Mon Nov 18 12:40:06 2019 -0500
+++ b/src/hotspot/share/memory/filemap.cpp	Tue Nov 19 18:45:08 2019 -0500
@@ -1133,7 +1133,7 @@
     assert((base - (char*)CompressedKlassPointers::base()) % HeapWordSize == 0, "Sanity");
     if (base != NULL) {
       _mapping_offset = (size_t)CompressedOops::encode_not_null((oop)base);
-      assert(_mapping_offset >> 32 == 0, "must be 32-bit only");
+      assert(_mapping_offset == (size_t)(uint32_t)_mapping_offset, "must be 32-bit only");
     }
   } else {
     if (base != NULL) {
@@ -1566,7 +1566,7 @@
 
 address FileMapInfo::decode_start_address(FileMapRegion* spc, bool with_current_oop_encoding_mode) {
   size_t offset = spc->mapping_offset();
-  assert((offset >> 32) == 0, "must be 32-bit only");
+  assert(offset == (size_t)(uint32_t)offset, "must be 32-bit only");
   uint n = (uint)offset;
   if (with_current_oop_encoding_mode) {
     return (address)CompressedOops::decode_not_null(n);
--- a/src/hotspot/share/runtime/thread.cpp	Mon Nov 18 12:40:06 2019 -0500
+++ b/src/hotspot/share/runtime/thread.cpp	Tue Nov 19 18:45:08 2019 -0500
@@ -1007,7 +1007,7 @@
   address end = os::current_stack_pointer();
   // Allow non Java threads to call this without stack_base
   if (_stack_base == NULL) return true;
-  if (stack_base() >= adr && adr >= end) return true;
+  if (stack_base() > adr && adr >= end) return true;
 
   return false;
 }
--- a/src/hotspot/share/runtime/thread.hpp	Mon Nov 18 12:40:06 2019 -0500
+++ b/src/hotspot/share/runtime/thread.hpp	Tue Nov 19 18:45:08 2019 -0500
@@ -729,7 +729,7 @@
 
   bool    on_local_stack(address adr) const {
     // QQQ this has knowledge of direction, ought to be a stack method
-    return (_stack_base >= adr && adr >= stack_end());
+    return (_stack_base > adr && adr >= stack_end());
   }
 
   int     lgrp_id() const        { return _lgrp_id; }
--- a/src/java.base/share/classes/java/lang/Class.java	Mon Nov 18 12:40:06 2019 -0500
+++ b/src/java.base/share/classes/java/lang/Class.java	Tue Nov 19 18:45:08 2019 -0500
@@ -325,6 +325,10 @@
      * @throws    ExceptionInInitializerError if the initialization provoked
      *            by this method fails
      * @throws    ClassNotFoundException if the class cannot be located
+     *
+     * @jls 12.2 Loading of Classes and Interfaces
+     * @jls 12.3 Linking of Classes and Interfaces
+     * @jls 12.4 Initialization of Classes and Interfaces
      */
     @CallerSensitive
     public static Class<?> forName(String className)
@@ -339,7 +343,7 @@
      * interface with the given string name, using the given class loader.
      * Given the fully qualified name for a class or interface (in the same
      * format returned by {@code getName}) this method attempts to
-     * locate, load, and link the class or interface.  The specified class
+     * locate and load the class or interface.  The specified class
      * loader is used to load the class or interface.  If the parameter
      * {@code loader} is null, the class is loaded through the bootstrap
      * class loader.  The class is initialized only if the
@@ -374,7 +378,7 @@
      * is accessible to its caller.
      *
      * @param name       fully qualified name of the desired class
-     * @param initialize if {@code true} the class will be initialized.
+     * @param initialize if {@code true} the class will be initialized (which implies linking).
      *                   See Section 12.4 of <em>The Java Language Specification</em>.
      * @param loader     class loader from which the class must be loaded
      * @return           class object representing the desired class
@@ -392,6 +396,10 @@
      *
      * @see       java.lang.Class#forName(String)
      * @see       java.lang.ClassLoader
+     *
+     * @jls 12.2 Loading of Classes and Interfaces
+     * @jls 12.3 Linking of Classes and Interfaces
+     * @jls 12.4 Initialization of Classes and Interfaces
      * @since     1.2
      */
     @CallerSensitive
@@ -427,9 +435,9 @@
      * Returns the {@code Class} with the given <a href="ClassLoader.html#binary-name">
      * binary name</a> in the given module.
      *
-     * <p> This method attempts to locate, load, and link the class or interface.
-     * It does not run the class initializer.  If the class is not found, this
-     * method returns {@code null}. </p>
+     * <p> This method attempts to locate and load the class or interface.
+     * It does not link the class, and does not run the class initializer.
+     * If the class is not found, this method returns {@code null}. </p>
      *
      * <p> If the class loader of the given module defines other modules and
      * the given name is a class defined in a different module, this method
@@ -465,6 +473,8 @@
      *         in a module.</li>
      *         </ul>
      *
+     * @jls 12.2 Loading of Classes and Interfaces
+     * @jls 12.3 Linking of Classes and Interfaces
      * @since 9
      * @spec JPMS
      */
--- a/src/java.base/share/classes/java/lang/module/Configuration.java	Mon Nov 18 12:40:06 2019 -0500
+++ b/src/java.base/share/classes/java/lang/module/Configuration.java	Tue Nov 19 18:45:08 2019 -0500
@@ -312,7 +312,7 @@
     {
         List<Configuration> parents = List.of(empty());
         Resolver resolver = new Resolver(finder, parents, ModuleFinder.of(), traceOutput);
-        resolver.resolve(roots).bind();
+        resolver.resolve(roots).bind(/*bindIncubatorModules*/false);
         return new Configuration(parents, resolver);
     }
 
--- a/src/java.base/share/classes/java/lang/module/Resolver.java	Mon Nov 18 12:40:06 2019 -0500
+++ b/src/java.base/share/classes/java/lang/module/Resolver.java	Tue Nov 19 18:45:08 2019 -0500
@@ -28,7 +28,6 @@
 import java.io.PrintStream;
 import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Requires.Modifier;
-import java.net.URI;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -45,6 +44,7 @@
 
 import jdk.internal.module.ModuleHashes;
 import jdk.internal.module.ModuleReferenceImpl;
+import jdk.internal.module.ModuleResolution;
 import jdk.internal.module.ModuleTarget;
 
 /**
@@ -215,15 +215,32 @@
      * service-use relation.
      */
     Resolver bind() {
+        return bind(/*bindIncubatorModules*/true);
+    }
 
+    /**
+     * Augments the set of resolved modules with modules induced by the
+     * service-use relation.
+     *
+     * @param bindIncubatorModules true if incubator modules are candidates to
+     *        add to the module graph
+     */
+    Resolver bind(boolean bindIncubatorModules) {
         // Scan the finders for all available service provider modules. As
         // java.base uses services then the module finders will be scanned
         // anyway.
         Map<String, Set<ModuleReference>> availableProviders = new HashMap<>();
         for (ModuleReference mref : findAll()) {
             ModuleDescriptor descriptor = mref.descriptor();
-            if (!descriptor.provides().isEmpty()) {
 
+            boolean candidate;
+            if (!bindIncubatorModules && (mref instanceof ModuleReferenceImpl)) {
+                ModuleResolution mres = ((ModuleReferenceImpl) mref).moduleResolution();
+                candidate = (mres == null) || (mres.hasIncubatingWarning() == false);
+            } else {
+                candidate = true;
+            }
+            if (candidate && !descriptor.provides().isEmpty()) {
                 for (Provides provides :  descriptor.provides()) {
                     String sn = provides.service();
 
--- a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Mon Nov 18 12:40:06 2019 -0500
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Tue Nov 19 18:45:08 2019 -0500
@@ -352,7 +352,7 @@
 
         Configuration cf;
         if (needResolution) {
-            cf = JLMA.resolveAndBind(finder, roots, traceOutput);
+            cf = Modules.newBootLayerConfiguration(finder, roots, traceOutput);
         } else {
             if (archivedModuleGraph != null) {
                 cf = archivedModuleGraph.configuration();
--- a/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java	Mon Nov 18 12:40:06 2019 -0500
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java	Tue Nov 19 18:45:08 2019 -0500
@@ -34,6 +34,7 @@
 import jdk.internal.org.objectweb.asm.ClassWriter;
 import jdk.internal.org.objectweb.asm.ModuleVisitor;
 import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.commons.ModuleResolutionAttribute;
 import jdk.internal.org.objectweb.asm.commons.ModuleTargetAttribute;
 import static jdk.internal.org.objectweb.asm.Opcodes.*;
 
@@ -78,7 +79,9 @@
      * Writes the given module descriptor to a module-info.class file,
      * returning it in a byte array.
      */
-    private static byte[] toModuleInfo(ModuleDescriptor md, ModuleTarget target) {
+    private static byte[] toModuleInfo(ModuleDescriptor md,
+                                       ModuleResolution mres,
+                                       ModuleTarget target) {
         ClassWriter cw = new ClassWriter(0);
         cw.visit(Opcodes.V10, ACC_MODULE, "module-info", null, null, null);
 
@@ -147,6 +150,11 @@
 
         mv.visitEnd();
 
+        // write ModuleResolution attribute if specified
+        if (mres != null) {
+            cw.visitAttribute(new ModuleResolutionAttribute(mres.value()));
+        }
+
         // write ModuleTarget attribute if there is a target platform
         if (target != null && target.targetPlatform().length() > 0) {
             cw.visitAttribute(new ModuleTargetAttribute(target.targetPlatform()));
@@ -161,11 +169,12 @@
      * module-info.class.
      */
     public static void write(ModuleDescriptor descriptor,
+                             ModuleResolution mres,
                              ModuleTarget target,
                              OutputStream out)
         throws IOException
     {
-        byte[] bytes = toModuleInfo(descriptor, target);
+        byte[] bytes = toModuleInfo(descriptor, mres, target);
         out.write(bytes);
     }
 
@@ -173,10 +182,34 @@
      * Writes a module descriptor to the given output stream as a
      * module-info.class.
      */
+    public static void write(ModuleDescriptor descriptor,
+                             ModuleResolution mres,
+                             OutputStream out)
+        throws IOException
+    {
+        write(descriptor, mres, null, out);
+    }
+
+    /**
+     * Writes a module descriptor to the given output stream as a
+     * module-info.class.
+     */
+    public static void write(ModuleDescriptor descriptor,
+                             ModuleTarget target,
+                             OutputStream out)
+        throws IOException
+    {
+        write(descriptor, null, target, out);
+    }
+
+    /**
+     * Writes a module descriptor to the given output stream as a
+     * module-info.class.
+     */
     public static void write(ModuleDescriptor descriptor, OutputStream out)
         throws IOException
     {
-        write(descriptor, null, out);
+        write(descriptor, null, null, out);
     }
 
     /**
@@ -184,7 +217,7 @@
      * in module-info.class format.
      */
     public static ByteBuffer toByteBuffer(ModuleDescriptor descriptor) {
-        byte[] bytes = toModuleInfo(descriptor, null);
+        byte[] bytes = toModuleInfo(descriptor, null, null);
         return ByteBuffer.wrap(bytes);
     }
 }
--- a/src/java.base/share/classes/jdk/internal/module/Modules.java	Mon Nov 18 12:40:06 2019 -0500
+++ b/src/java.base/share/classes/jdk/internal/module/Modules.java	Tue Nov 19 18:45:08 2019 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
 
 package jdk.internal.module;
 
+import java.io.PrintStream;
 import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleFinder;
@@ -33,6 +34,7 @@
 import java.net.URI;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -40,6 +42,7 @@
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
+import jdk.internal.access.JavaLangModuleAccess;
 import jdk.internal.loader.BootLoader;
 import jdk.internal.loader.BuiltinClassLoader;
 import jdk.internal.loader.ClassLoaders;
@@ -61,6 +64,7 @@
     private Modules() { }
 
     private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
+    private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
 
     /**
      * Creates a new Module. The module has the given ModuleDescriptor and
@@ -159,6 +163,20 @@
     }
 
     /**
+     * Resolves a collection of root modules, with service binding and the empty
+     * Configuration as the parent to create a Configuration for the boot layer.
+     *
+     * This method is intended to be used to create the Configuration for the
+     * boot layer during startup or at a link-time.
+     */
+    public static Configuration newBootLayerConfiguration(ModuleFinder finder,
+                                                          Collection<String> roots,
+                                                          PrintStream traceOutput)
+    {
+        return JLMA.resolveAndBind(finder, roots, traceOutput);
+    }
+
+    /**
      * Called by the VM when code in the given Module has been transformed by
      * an agent and so may have been instrumented to call into supporting
      * classes on the boot class path or application class path.
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java	Mon Nov 18 12:40:06 2019 -0500
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java	Tue Nov 19 18:45:08 2019 -0500
@@ -384,14 +384,14 @@
     Address stackBase = getStackBase();
     // Be robust
     if (sp == null) return false;
-    return stackBase.greaterThanOrEqual(a) && sp.lessThanOrEqual(a);
+    return stackBase.greaterThan(a) && sp.lessThanOrEqual(a);
   }
 
   public boolean isLockOwned(Address a) {
     Address stackBase = getStackBase();
     Address stackLimit = stackBase.addOffsetTo(-getStackSize());
 
-    return stackBase.greaterThanOrEqual(a) && stackLimit.lessThanOrEqual(a);
+    return stackBase.greaterThan(a) && stackLimit.lessThanOrEqual(a);
 
     // FIXME: should traverse MonitorArray/MonitorChunks as in VM
   }
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java	Mon Nov 18 12:40:06 2019 -0500
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java	Tue Nov 19 18:45:08 2019 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -61,6 +61,7 @@
 import jdk.internal.module.Checks;
 import jdk.internal.module.DefaultRoots;
 import jdk.internal.module.IllegalAccessMaps;
+import jdk.internal.module.Modules;
 import jdk.internal.module.ModuleHashes;
 import jdk.internal.module.ModuleInfo.Attributes;
 import jdk.internal.module.ModuleInfoExtender;
@@ -291,10 +292,10 @@
 
     /**
      * Resolves a collection of root modules, with service binding, to create
-     * configuration.
+     * a Configuration for the boot layer.
      */
     private Configuration resolve(ModuleFinder finder, Set<String> roots) {
-        return Configuration.empty().resolveAndBind(finder, ModuleFinder.of(), roots);
+        return Modules.newBootLayerConfiguration(finder, roots, null);
     }
 
     /**
--- a/test/hotspot/jtreg/compiler/codegen/TestCharVect2.java	Mon Nov 18 12:40:06 2019 -0500
+++ b/test/hotspot/jtreg/compiler/codegen/TestCharVect2.java	Tue Nov 19 18:45:08 2019 -0500
@@ -24,9 +24,17 @@
 /**
  * @test
  * @bug 8001183
- * @summary incorrect results of char vectors right shift operaiton
+ * @summary incorrect results of char vectors right shift operation
  *
  * @run main/othervm/timeout=400 -Xbatch -Xmx128m compiler.codegen.TestCharVect2
+ */
+
+/**
+ * @test
+ * @bug 8001183
+ * @summary incorrect results of char vectors right shift operation
+ * @requires vm.compiler2.enabled | vm.graal.enabled
+ *
  * @run main/othervm/timeout=400 -Xbatch -Xmx128m -XX:MaxVectorSize=8 compiler.codegen.TestCharVect2
  * @run main/othervm/timeout=400 -Xbatch -Xmx128m -XX:MaxVectorSize=16 compiler.codegen.TestCharVect2
  * @run main/othervm/timeout=400 -Xbatch -Xmx128m -XX:MaxVectorSize=32 compiler.codegen.TestCharVect2
--- a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/AnonVmClassesDuringDump.java	Mon Nov 18 12:40:06 2019 -0500
+++ b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/AnonVmClassesDuringDump.java	Tue Nov 19 18:45:08 2019 -0500
@@ -32,16 +32,15 @@
  * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes
  * @requires vm.cds
  * @requires vm.flavor != "minimal"
- * @build AnonVmClassesDuringDumpTransformer Hello
- * @run main/othervm AnonVmClassesDuringDump
+ * @run driver AnonVmClassesDuringDump
  */
 
 public class AnonVmClassesDuringDump {
     public static String appClasses[] = {
-        "Hello",
+        Hello.class.getName(),
     };
     public static String agentClasses[] = {
-        "AnonVmClassesDuringDumpTransformer",
+        AnonVmClassesDuringDumpTransformer.class.getName(),
     };
 
     public static String cdsDiagnosticOption = "-XX:+AllowArchivingWithJavaAgent";
@@ -55,7 +54,7 @@
         String appJar =
             ClassFileInstaller.writeJar("AnonVmClassesDuringDumpApp.jar", appClasses);
 
-        TestCommon.testDump(appJar, TestCommon.list("Hello"),
+        TestCommon.testDump(appJar, TestCommon.list(Hello.class.getName()),
                             "-javaagent:" + agentJar,
                             "-XX:+UnlockDiagnosticVMOptions", cdsDiagnosticOption,
                             // Set the following property to see logs for dynamically generated classes
@@ -71,13 +70,13 @@
         String pattern = prefix + class_pattern + suffix;
         // during run time, anonymous classes shouldn't be loaded from the archive
         TestCommon.run("-cp", appJar,
-            "-XX:+UnlockDiagnosticVMOptions", cdsDiagnosticOption, "Hello")
+            "-XX:+UnlockDiagnosticVMOptions", cdsDiagnosticOption, Hello.class.getName())
             .assertNormalExit(output -> output.shouldNotMatch(pattern));
 
         // inspect the archive and make sure no anonymous class is in there
         TestCommon.run("-cp", appJar,
             "-XX:+UnlockDiagnosticVMOptions", cdsDiagnosticOption,
-            "-XX:+PrintSharedArchiveAndExit", "-XX:+PrintSharedDictionary", "Hello")
+            "-XX:+PrintSharedArchiveAndExit", "-XX:+PrintSharedDictionary", Hello.class.getName())
             .assertNormalExit(output -> output.shouldNotMatch(class_pattern));
     }
 }
--- a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/ArrayTest.java	Mon Nov 18 12:40:06 2019 -0500
+++ b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/ArrayTest.java	Tue Nov 19 18:45:08 2019 -0500
@@ -28,7 +28,6 @@
  * @requires vm.cds
  * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
  * @modules jdk.jartool/sun.tools.jar
- * @compile ArrayTestHelper.java
  * @build sun.hotspot.WhiteBox
  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
  * @run driver ArrayTest
@@ -41,7 +40,7 @@
 public class ArrayTest {
 
     static String arrayClasses[] = {
-        "ArrayTestHelper",
+        ArrayTestHelper.class.getName(),
         "[Ljava/lang/Comparable;",
         "[I",
         "[[[Ljava/lang/Object;",
@@ -70,7 +69,7 @@
         argsList.add("-cp");
         argsList.add(appJar);
         argsList.add(bootClassPath);
-        argsList.add("ArrayTestHelper");
+        argsList.add(ArrayTestHelper.class.getName());
         // the following are input args to the ArrayTestHelper.
         // skip checking array classes during run time
         for (int i = 0; i < 1; i++) {
--- a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/GCDuringDump.java	Mon Nov 18 12:40:06 2019 -0500
+++ b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/GCDuringDump.java	Tue Nov 19 18:45:08 2019 -0500
@@ -28,8 +28,7 @@
  * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes
  * @requires vm.cds
  * @requires vm.flavor != "minimal"
- * @build GCDuringDumpTransformer Hello
- * @run main/othervm GCDuringDump
+ * @run driver GCDuringDump
  */
 
 import jdk.test.lib.cds.CDSOptions;
@@ -38,10 +37,10 @@
 
 public class GCDuringDump {
     public static String appClasses[] = {
-        "Hello",
+        Hello.class.getName(),
     };
     public static String agentClasses[] = {
-        "GCDuringDumpTransformer",
+        GCDuringDumpTransformer.class.getName(),
     };
 
     public static void main(String[] args) throws Throwable {
@@ -63,7 +62,7 @@
             String extraArg = (i == 0) ? "-showversion" : "-javaagent:" + agentJar;
             String extraOption = (i == 0) ? "-showversion" : "-XX:+AllowArchivingWithJavaAgent";
 
-            TestCommon.testDump(appJar, TestCommon.list("Hello"),
+            TestCommon.testDump(appJar, TestCommon.list(Hello.class.getName()),
                                 "-XX:+UnlockDiagnosticVMOptions", extraOption,
                                 extraArg, "-Xmx32m", gcLog);
 
@@ -73,7 +72,7 @@
                 "-XX:+PrintSharedSpaces",
                 "-XX:+UnlockDiagnosticVMOptions", extraOption,
                 gcLog,
-                "Hello")
+                Hello.class.getName())
               .assertNormalExit();
         }
     }
--- a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/GCSharedStringsDuringDump.java	Mon Nov 18 12:40:06 2019 -0500
+++ b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/GCSharedStringsDuringDump.java	Tue Nov 19 18:45:08 2019 -0500
@@ -29,9 +29,9 @@
  * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes
  * @requires vm.cds.archived.java.heap
  * @modules jdk.jartool/sun.tools.jar
- * @build sun.hotspot.WhiteBox GCDuringDumpTransformer GCSharedStringsDuringDumpWb
+ * @build sun.hotspot.WhiteBox
  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
- * @run main/othervm/timeout=480 GCSharedStringsDuringDump
+ * @run driver/timeout=480 GCSharedStringsDuringDump
  */
 
 import java.io.File;
@@ -41,14 +41,13 @@
 import jdk.test.lib.cds.CDSOptions;
 import jdk.test.lib.process.OutputAnalyzer;
 import jdk.test.lib.process.ProcessTools;
-import sun.hotspot.WhiteBox;
 
 public class GCSharedStringsDuringDump {
     public static String appClasses[] = {
-        "GCSharedStringsDuringDumpWb",
+        GCSharedStringsDuringDumpWb.class.getName(),
     };
     public static String agentClasses[] = {
-        "GCDuringDumpTransformer",
+        GCDuringDumpTransformer.class.getName(),
     };
 
     public static void main(String[] args) throws Throwable {
@@ -88,7 +87,7 @@
             String extraArg = (i == 0) ? "-showversion" : "-javaagent:" + agentJar;
             String extraOption = (i == 0) ? "-showversion" : "-XX:+AllowArchivingWithJavaAgent";
             OutputAnalyzer output = TestCommon.dump(
-                                appJar, TestCommon.list("GCSharedStringsDuringDumpWb"),
+                                appJar, TestCommon.list(GCSharedStringsDuringDumpWb.class.getName()),
                                 bootClassPath, extraArg, "-Xmx32m", gcLog,
                                 "-XX:SharedArchiveConfigFile=" + sharedArchiveCfgFile,
                                 "-XX:+UnlockDiagnosticVMOptions", extraOption);
@@ -101,7 +100,7 @@
                 // Try again with larger heap and NewSize, this should increase the
                 // G1 heap region size to 2M
                 TestCommon.testDump(
-                    appJar, TestCommon.list("GCSharedStringsDuringDumpWb"),
+                    appJar, TestCommon.list(GCSharedStringsDuringDumpWb.class.getName()),
                     bootClassPath, extraArg, "-Xmx8g", "-XX:NewSize=8m", gcLog,
                     "-XX:SharedArchiveConfigFile=" + sharedArchiveCfgFile,
                     "-XX:+UnlockDiagnosticVMOptions", extraOption);
@@ -119,7 +118,7 @@
                 "-XX:+WhiteBoxAPI",
                 "-XX:SharedReadOnlySize=30m",
                 gcLog,
-                "GCSharedStringsDuringDumpWb")
+                GCSharedStringsDuringDumpWb.class.getName())
               .assertNormalExit();
         }
     }
--- a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/HumongousDuringDump.java	Mon Nov 18 12:40:06 2019 -0500
+++ b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/HumongousDuringDump.java	Tue Nov 19 18:45:08 2019 -0500
@@ -28,8 +28,7 @@
  * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes
  * @requires vm.cds.archived.java.heap
  * @requires vm.flavor != "minimal"
- * @build HumongousDuringDumpTransformer Hello
- * @run main/othervm/timeout=240 HumongousDuringDump
+ * @run driver/timeout=240 HumongousDuringDump
  */
 
 import jdk.test.lib.cds.CDSOptions;
@@ -38,10 +37,10 @@
 
 public class HumongousDuringDump {
     public static String appClasses[] = {
-        "Hello",
+        Hello.class.getName(),
     };
     public static String agentClasses[] = {
-        "HumongousDuringDumpTransformer",
+        HumongousDuringDumpTransformer.class.getName(),
     };
 
     public static void main(String[] args) throws Throwable {
@@ -60,7 +59,7 @@
         String extraOption = "-XX:+AllowArchivingWithJavaAgent";
 
         OutputAnalyzer out =
-          TestCommon.testDump(appJar, TestCommon.list("Hello"),
+          TestCommon.testDump(appJar, TestCommon.list(Hello.class.getName()),
                               "-XX:+UnlockDiagnosticVMOptions", extraOption,
                               "-Xlog:gc+region+cds",
                               "-Xlog:gc+region=trace",
@@ -79,7 +78,7 @@
                 "-XX:+PrintSharedSpaces",
                 "-XX:+UnlockDiagnosticVMOptions", extraOption,
                 gcLog,
-                "Hello")
+                Hello.class.getName())
               .assertNormalExit();
     }
 }
--- a/test/hotspot/jtreg/serviceability/tmtools/share/common/ToolRunner.java	Mon Nov 18 12:40:06 2019 -0500
+++ b/test/hotspot/jtreg/serviceability/tmtools/share/common/ToolRunner.java	Tue Nov 19 18:45:08 2019 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,15 +22,11 @@
  */
 package common;
 
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.StringTokenizer;
-import jdk.test.lib.process.OutputAnalyzer;
-import jdk.test.lib.process.ProcessTools;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.time.Instant;
 
 /**
  * This class starts a process specified by the passed command line waits till
@@ -38,14 +34,10 @@
  * output as ToolResults
  */
 class ToolRunner {
-
-    private final List<String> cmdArgs = new LinkedList<>();
+    private final String[] cmdArgs;
 
     ToolRunner(String cmdLine) {
-        StringTokenizer st = new StringTokenizer(cmdLine);
-        while (st.hasMoreTokens()) {
-            cmdArgs.add(st.nextToken());
-        }
+        cmdArgs = cmdLine.split(" +");
     }
 
     /**
@@ -56,23 +48,18 @@
      * @throws Exception if anything goes wrong
      */
     ToolResults runToCompletion() throws Exception {
-
         ProcessBuilder pb = new ProcessBuilder(cmdArgs);
-        OutputAnalyzer oa = ProcessTools.executeProcess(pb);
-
-        return new ToolResults(oa.getExitValue(),
-                stringToList(oa.getStdout()),
-                stringToList(oa.getStderr()));
+        Path out = Files.createTempFile(Paths.get("."), "out.", ".txt");
+        Path err = out.resolveSibling(out.getFileName().toString().replaceFirst("out", "err"));
 
-    }
-
-    private static List<String> stringToList(String s) throws IOException {
-        BufferedReader reader = new BufferedReader(new StringReader(s));
-        List<String> strings = new ArrayList<>();
-        for (String line = reader.readLine(); line != null; line = reader.readLine()) {
-            strings.add(line);
-        }
-        reader.close();
-        return strings;
+        Process p = pb.redirectOutput(ProcessBuilder.Redirect.to(out.toFile()))
+                      .redirectError(ProcessBuilder.Redirect.to(err.toFile()))
+                      .start();
+        System.out.printf("[%s] started process %d %s with out/err redirected to '%s' and '%s'%n",
+                Instant.now().toString(), p.pid(), pb.command(), out.toString(), err.toString());
+        int exitCode = p.waitFor();
+        System.out.printf("[%s] process %d finished with exit code = %d%n",
+                Instant.now().toString(), p.pid(), exitCode);
+        return new ToolResults(exitCode, Files.readAllLines(out), Files.readAllLines(err));
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/Class/forName/NonLinking/Container.java	Tue Nov 19 18:45:08 2019 -0500
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public class Container {
+
+    public Container(MissingClass m) {}
+
+    public Container() {
+        this(new MissingClass() {});
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/Class/forName/NonLinking/MissingClass.java	Tue Nov 19 18:45:08 2019 -0500
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public class MissingClass {}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/Class/forName/NonLinking/NonLinking.java	Tue Nov 19 18:45:08 2019 -0500
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/*
+ * @test
+ * @bug 8231924 8233091 8233272
+ * @summary Confirm load (but not link) behavior of Class.forName()
+ * @library /test/lib
+ *
+ * @compile MissingClass.java Container.java
+ *
+ * @run driver ClassFileInstaller -jar classes.jar Container Container$1
+ *
+ * @run main/othervm NonLinking init
+ * @run main/othervm NonLinking load
+ */
+/*
+ * The @compile and '@main ClassFileInstaller' tasks above create a classes.jar
+ * file containing the .class file for Container, but not MissingClass.
+ */
+
+public class NonLinking {
+    public static void main(String[] args) throws Throwable {
+        Path jarPath = Paths.get("classes.jar");
+        URL url = jarPath.toUri().toURL();
+        URLClassLoader ucl1 = new URLClassLoader("UCL1",
+                                                 new URL[] { url },
+                                                 null); // Don't delegate
+        switch(args[0]) {
+            case "init":
+                try {
+                    // Trying to initialize Container without MissingClass -> NCDFE
+                    Class.forName("Container", true, ucl1);
+                    throw new RuntimeException("Missed expected NoClassDefFoundError");
+                } catch (NoClassDefFoundError expected) {
+                    final String CLASSNAME = "MissingClass";
+                    Throwable cause = expected.getCause();
+                    if (!cause.getMessage().contains(CLASSNAME)) {
+                        throw new RuntimeException("Cause of NoClassDefFoundError does not contain \"" + CLASSNAME + "\"", cause);
+                    }
+                }
+                break;
+            case "load":
+                // Loading (but not linking) Container will succeed.
+                // Before 8233091, this fails with NCDFE due to linking.
+                Class.forName("Container", false, ucl1);
+                break;
+            default:
+                throw new RuntimeException("Unknown command: " + args[0]);
+        }
+    }
+}
--- a/test/jdk/jdk/modules/etc/DefaultModules.java	Mon Nov 18 12:40:06 2019 -0500
+++ b/test/jdk/jdk/modules/etc/DefaultModules.java	Tue Nov 19 18:45:08 2019 -0500
@@ -59,8 +59,8 @@
         String testSrc = System.getProperty("test.src");
 
         // $JDK_HOME/bin/java TestModules.java
-        String source = Path.of(testSrc, "src", "TestRootModules.java").toString();
-        ProcessTools.executeTestJava(source)
+        String source = Path.of(testSrc, "TestRootModules.java").toString();
+        ProcessTools.executeTestJava("--add-exports", "java.base/jdk.internal.module=ALL-UNNAMED", source)
                 .outputTo(System.out)
                 .errorTo(System.err)
                 .shouldHaveExitValue(0);
@@ -89,15 +89,18 @@
                 javaLauncher += ".exe";
 
             // $CUSTOM_JDK/bin/java TestRootModules.java
-            source = Path.of(testSrc, "src", "TestRootModules.java").toString();
-            out.format("Command line: [%s %s]%n", javaLauncher, source);
-            ProcessTools.executeProcess(new ProcessBuilder(javaLauncher, source))
+            source = Path.of(testSrc, "TestRootModules.java").toString();
+            ProcessBuilder pb = new ProcessBuilder(javaLauncher,
+                    "--add-exports", "java.base/jdk.internal.module=ALL-UNNAMED",
+                    source);
+            out.format("Command line: [%s]%n", pb.command());
+            ProcessTools.executeProcess(pb)
                     .outputTo(System.out)
                     .errorTo(System.err)
                     .shouldHaveExitValue(0);
 
             // $CUSTOM_JDK/bin/java TestJson.java
-            source = Path.of(testSrc, "src", "TestJson.java").toString();
+            source = Path.of(testSrc, "TestJson.java").toString();
             out.format("Command line: [%s %s]%n", javaLauncher, source);
             ProcessTools.executeProcess(new ProcessBuilder(javaLauncher, source))
                     .outputTo(System.out)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/modules/etc/TestJson.java	Tue Nov 19 18:45:08 2019 -0500
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.json.*;
+import java.io.InputStream;
+
+/**
+ * Exercise APIs exported by the java.json module
+ */
+
+public class TestJson {
+    public static void main(String[] args) {
+        JsonParser parser = Json.createParser(InputStream.nullInputStream());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/modules/etc/TestRootModules.java	Tue Nov 19 18:45:08 2019 -0500
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+
+import jdk.internal.module.ModuleResolution;
+
+/**
+ * Test the set of modules in the boot layer includes all modules that export
+ * an API. Also test that java.se is not resolved.
+ */
+
+public class TestRootModules {
+    public static void main(String[] args) {
+        // all modules that export an API should be resolved
+        // For now, this test ignores the ModuleResolution attribute
+        ModuleLayer bootLayer = ModuleLayer.boot();
+        ModuleFinder.ofSystem().findAll().stream()
+            .filter(mref -> !ModuleResolution.doNotResolveByDefault(mref))
+            .map(ModuleReference::descriptor)
+            .filter(descriptor -> descriptor.exports()
+                    .stream()
+                    .filter(e -> !e.isQualified())
+                    .findAny()
+                    .isPresent())
+            .map(ModuleDescriptor::name)
+            .forEach(name -> {
+                if (!bootLayer.findModule(name).isPresent())
+                    throw new RuntimeException(name + " not in boot layer");
+            });
+
+        // java.se should not be resolved
+        ModuleLayer.boot()
+                .findModule("java.se")
+                .map(m -> { throw new RuntimeException("java.se should not be resolved"); });
+    }
+}
--- a/test/jdk/jdk/modules/etc/src/TestJson.java	Mon Nov 18 12:40:06 2019 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import javax.json.*;
-import java.io.InputStream;
-
-/**
- * Exercise APIs exported by the java.json module
- */
-
-public class TestJson {
-    public static void main(String[] args) {
-        JsonParser parser = Json.createParser(InputStream.nullInputStream());
-    }
-}
--- a/test/jdk/jdk/modules/etc/src/TestRootModules.java	Mon Nov 18 12:40:06 2019 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleFinder;
-import java.lang.module.ModuleReference;
-
-/**
- * Test the set of modules in the boot layer includes all modules that export
- * an API. Also test that java.se is not resolved.
- */
-
-public class TestRootModules {
-    public static void main(String[] args) {
-        // all modules that export an API should be resolved
-        // For now, this test ignores the ModuleResolution attribute
-        ModuleLayer bootLayer = ModuleLayer.boot();
-        ModuleFinder.ofSystem().findAll().stream()
-            .map(ModuleReference::descriptor)
-            .filter(descriptor -> descriptor.exports()
-                    .stream()
-                    .filter(e -> !e.isQualified())
-                    .findAny()
-                    .isPresent())
-            .map(ModuleDescriptor::name)
-            .forEach(name -> {
-                if (!bootLayer.findModule(name).isPresent())
-                    throw new RuntimeException(name + " not in boot layer");
-            });
-
-        // java.se should not be resolved
-        ModuleLayer.boot()
-                .findModule("java.se")
-                .map(m -> { throw new RuntimeException("java.se should not be resolved"); });
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/modules/incubator/ServiceBinding.java	Tue Nov 19 18:45:08 2019 -0500
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8233922
+ * @modules java.base/jdk.internal.module
+ * @library /test/lib
+ * @build ServiceBinding TestBootLayer
+ * @run testng ServiceBinding
+ * @summary Test service binding with incubator modules
+ */
+
+import java.io.File;
+import java.io.OutputStream;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ResolvedModule;
+import java.nio.file.Path;
+import java.nio.file.Files;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.Stream;
+
+import static java.lang.module.ModuleDescriptor.newModule;
+
+import jdk.internal.module.ModuleInfoWriter;
+import jdk.internal.module.ModuleResolution;
+
+import org.testng.annotations.Test;
+
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.process.OutputAnalyzer;
+
+@Test
+public class ServiceBinding {
+    private static final Path HERE = Path.of(".");
+
+    /**
+     * module m1 uses p.S
+     * (incubating) module m2 requires m1 provides p.S
+     */
+    public void test1() throws Exception {
+        Path mlib = Files.createTempDirectory(HERE, "mlib");
+
+        var m1 = newModule("m1").exports("p").uses("p.S").build();
+        var m2 = newModule("m2").requires("m1").provides("p.S", List.of("impl.S1")).build();
+
+        writeModule(mlib, m1);
+        writeIncubatingModule(mlib, m2);
+
+        // boot layer: root=m1, incubator module m2 should not be resolved
+        testBootLayer(mlib, Set.of("m1"), Set.of("m1"), Set.of("m2"))
+                .shouldNotMatch("WARNING:.*m2");
+
+        // custom configuration: root=m1, incubator module m2 should be resolved
+        testCustomConfiguration(mlib, Set.of("m1"), Set.of("m2"));
+    }
+
+    /**
+     * module m1 uses p.S
+     * (incubating) module m2 requires m1 provides P.S uses q.S
+     * (incubating) module m3 requires m2 provides q.S
+     */
+    public void test2() throws Exception {
+        Path mlib = Files.createTempDirectory("mlib");
+
+        var m1 = newModule("m1").exports("p").uses("p.S").build();
+        var m2 = newModule("m2")
+                .requires("m1")
+                .provides("p.S", List.of("impl.S1"))
+                .exports("q")
+                .uses("q.S")
+                .build();
+        var m3 = newModule("m3").requires("m2").provides("q.S", List.of("impl.S1")).build();
+
+        writeModule(mlib, m1);
+        writeIncubatingModule(mlib, m2);
+        writeIncubatingModule(mlib, m3);
+
+        // boot layer: root=m1, incubator modules m2 and m3 should not be resolved
+        testBootLayer(mlib, Set.of("m1"), Set.of("m1"), Set.of("m2", "m3"))
+                .shouldNotMatch("WARNING:.*m2")
+                .shouldNotMatch("WARNING:.*m3");
+
+        // boot layer: root=m2, incubator module m3 should not be resolved
+        testBootLayer(mlib, Set.of("m2"), Set.of("m1", "m2"), Set.of("m3"))
+                .shouldMatch("WARNING:.*m2")
+                .shouldNotMatch("WARNING:.*m3");
+
+        // custom configuration: root=m1, incubator modules m2 and m3 should be resolved
+        testCustomConfiguration(mlib, Set.of("m1"), Set.of("m1", "m2", "m3"));
+
+        // custom configuration: root=m2, incubator module m3 should be resolved
+        testCustomConfiguration(mlib, Set.of("m2"), Set.of("m1", "m2", "m3"));
+    }
+
+    /**
+     * Creates an exploded module on the file system.
+     *
+     * @param mlib the top-level module directory
+     * @param descriptor the module descriptor of the module to write
+     */
+    void writeModule(Path mlib, ModuleDescriptor descriptor) throws Exception {
+        writeModule(mlib, descriptor, false);
+    }
+
+    /**
+     * Creates an exploded module on the file system. The module will be an
+     * incubating module.
+     *
+     * @param mlib the top-level module directory
+     * @param descriptor the module descriptor of the module to write
+     */
+    void writeIncubatingModule(Path mlib, ModuleDescriptor descriptor) throws Exception {
+        writeModule(mlib, descriptor, true);
+    }
+
+    /**
+     * Creates an exploded module on the file system.
+     *
+     * @param mlib the top-level module directory
+     * @param descriptor the module descriptor of the module to write
+     * @param incubating to create an incubating module
+     */
+    void writeModule(Path mlib, ModuleDescriptor descriptor, boolean incubating)
+        throws Exception
+    {
+        // create ModuleResolution attribute if incubating module
+        ModuleResolution mres = (incubating) ? ModuleResolution.empty().withIncubating() : null;
+        String name = descriptor.name();
+
+        // create directory for module
+        Path dir = Files.createDirectory(mlib.resolve(name));
+
+        // module-info.class
+        try (OutputStream out = Files.newOutputStream(dir.resolve("module-info.class"))) {
+            ModuleInfoWriter.write(descriptor, mres, out);
+        }
+
+        // create a dummy class file for each package
+        for (String pn : descriptor.packages()) {
+            Path subdir = dir.resolve(pn.replace('.', File.separatorChar));
+            Files.createDirectories(subdir);
+            Files.createFile(subdir.resolve("C.class"));
+        }
+    }
+
+    /**
+     * Run TestBootLayer in a child VM with the given module path and the
+     * --add-modules option with additional root modules. TestBootLayer checks
+     * the modules in the boot layer.
+     *
+     * @param mlib the module path
+     * @param roots the modules to specify to --add-modules
+     * @param expected the names of modules that should be in the boot layer
+     * @param notExpected the names of modules that should not be in boot layer
+     */
+    OutputAnalyzer testBootLayer(Path mlib,
+                                 Set<String> roots,
+                                 Set<String> expected,
+                                 Set<String> notExpected)
+        throws Exception
+    {
+        var opts = Stream.of("-p", mlib.toString(),
+                             "--add-modules", commaSeparated(roots),
+                             "TestBootLayer", commaSeparated(expected), commaSeparated(notExpected));
+        return ProcessTools.executeTestJava(opts.toArray(String[]::new))
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .shouldHaveExitValue(0);
+    }
+
+    /**
+     * Creates a Configuration by resolving a set of root modules, with service
+     * binding, then checks that the Configuration includes the expected modules.
+     *
+     * @param mlib the module path
+     * @param roots the names of the root modules
+     * @param expected the names of modules that should be in the configuration
+     */
+    void testCustomConfiguration(Path mlib, Set<String> roots, Set<String> expected) {
+        ModuleFinder finder = ModuleFinder.of(mlib);
+        Configuration cf = ModuleLayer.boot()
+                .configuration()
+                .resolveAndBind(finder, ModuleFinder.of(), roots);
+
+        Set<String> modules = cf.modules().stream()
+                .map(ResolvedModule::name)
+                .collect(Collectors.toSet());
+
+        expected.stream()
+                .filter(mn -> !modules.contains(mn))
+                .findAny()
+                .ifPresent(mn -> {
+                    throw new RuntimeException(mn + " not in configuration!!!");
+                });
+    }
+
+    String commaSeparated(Set<String> s) {
+        return s.stream().collect(Collectors.joining(","));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/modules/incubator/TestBootLayer.java	Tue Nov 19 18:45:08 2019 -0500
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * Launched by the test ServiceBinding to test modules in the boot layer.
+ */
+
+public class TestBootLayer {
+    public static void main(String[] args) throws Exception {
+        Pattern splitter = Pattern.compile(",");
+
+        // the names of all modules in the boot layer
+        Set<String> modules = ModuleLayer.boot().modules().stream()
+                .map(Module::getName)
+                .collect(Collectors.toSet());
+
+        // throw exception if an expected module is not in the boot layer
+        splitter.splitAsStream(args[0])
+                .filter(Predicate.not(String::isEmpty))
+                .filter(mn -> !modules.contains(mn))
+                .findAny()
+                .ifPresent(mn -> {
+                    throw new RuntimeException(mn + " not in boot layer!!!");
+                });
+
+        // throw exception if an unexpected module is in the boot layer
+        splitter.splitAsStream(args[1])
+                .filter(Predicate.not(String::isEmpty))
+                .filter(mn -> modules.contains(mn))
+                .findAny()
+                .ifPresent(mn -> {
+                    throw new RuntimeException(mn + " in boot layer!!!!");
+                });
+    }
+}
\ No newline at end of file