--- 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