--- a/doc/building.html Mon Aug 27 16:01:38 2018 -0400
+++ b/doc/building.html Mon Aug 27 16:02:55 2018 -0400
@@ -72,6 +72,7 @@
<li><a href="#specifying-the-target-platform">Specifying the Target Platform</a></li>
<li><a href="#toolchain-considerations">Toolchain Considerations</a></li>
<li><a href="#native-libraries">Native Libraries</a></li>
+<li><a href="#creating-and-using-sysroots-with-qemu-deboostrap">Creating And Using Sysroots With qemu-deboostrap</a></li>
<li><a href="#building-for-armaarch64">Building for ARM/aarch64</a></li>
<li><a href="#verifying-the-build">Verifying the Build</a></li>
</ul></li>
@@ -634,6 +635,72 @@
cp: cannot stat `arm-linux-gnueabihf/libXt.so': No such file or directory</code></pre></li>
<li><p>If the X11 libraries are not properly detected by <code>configure</code>, you can point them out by <code>--with-x</code>.</p></li>
</ul>
+<h3 id="creating-and-using-sysroots-with-qemu-deboostrap">Creating And Using Sysroots With qemu-deboostrap</h3>
+<p>Fortunately, you can create sysroots for foreign architectures with tools provided by your OS. On Debian/Ubuntu systems, one could use <code>qemu-deboostrap</code> to create the <em>target</em> system chroot, which would have the native libraries and headers specific to that <em>target</em> system. After that, we can use the cross-compiler on the <em>build</em> system, pointing into chroot to get the build dependencies right. This allows building for foreign architectures with native compilation speed.</p>
+<p>For example, cross-compiling to AArch64 from x86_64 could be done like this:</p>
+<ul>
+<li><p>Install cross-compiler on the <em>build</em> system:</p>
+<pre><code>apt install g++-aarch64-linux-gnu gcc-aarch64-linux-gnu</code></pre></li>
+<li><p>Create chroot on the <em>build</em> system, configuring it for <em>target</em> system:</p>
+<pre><code>sudo qemu-debootstrap --arch=arm64 --verbose \
+ --include=fakeroot,build-essential,libx11-dev,libxext-dev,libxrender-dev,libxtst-dev,libxt-dev,libcups2-dev,libfontconfig1-dev,libasound2-dev,libfreetype6-dev,libpng12-dev \
+ --resolve-deps jessie /chroots/arm64 http://httpredir.debian.org/debian/</code></pre></li>
+<li><p>Configure and build with newly created chroot as sysroot/toolchain-path:</p>
+<pre><code>CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++ sh ./configure --openjdk-target=aarch64-linux-gnu --with-sysroot=/chroots/arm64/ --with-toolchain-path=/chroots/arm64/
+make images
+ls build/linux-aarch64-normal-server-release/</code></pre></li>
+</ul>
+<p>The build does not create new files in that chroot, so it can be reused for multiple builds without additional cleanup.</p>
+<p>Architectures that are known to successfully cross-compile like this are:</p>
+<table>
+<thead>
+<tr class="header">
+<th style="text-align: left;">Target</th>
+<th style="text-align: left;"><code>CC</code></th>
+<th style="text-align: left;"><code>CXX</code></th>
+<th><code>--arch=...</code></th>
+<th><code>--openjdk-target=...</code></th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td style="text-align: left;">x86</td>
+<td style="text-align: left;">default</td>
+<td style="text-align: left;">default</td>
+<td>i386</td>
+<td>i386-linux-gnu</td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">armhf</td>
+<td style="text-align: left;">gcc-arm-linux-gnueabihf</td>
+<td style="text-align: left;">g++-arm-linux-gnueabihf</td>
+<td>armhf</td>
+<td>arm-linux-gnueabihf</td>
+</tr>
+<tr class="odd">
+<td style="text-align: left;">aarch64</td>
+<td style="text-align: left;">gcc-aarch64-linux-gnu</td>
+<td style="text-align: left;">g++-aarch64-linux-gnu</td>
+<td>arm64</td>
+<td>aarch64-linux-gnu</td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">ppc64el</td>
+<td style="text-align: left;">gcc-powerpc64le-linux-gnu</td>
+<td style="text-align: left;">g++-powerpc64le-linux-gnu</td>
+<td>ppc64el</td>
+<td>powerpc64le-linux-gnu</td>
+</tr>
+<tr class="odd">
+<td style="text-align: left;">s390x</td>
+<td style="text-align: left;">gcc-s390x-linux-gnu</td>
+<td style="text-align: left;">g++-s390x-linux-gnu</td>
+<td>s390x</td>
+<td>s390x-linux-gnu</td>
+</tr>
+</tbody>
+</table>
+<p>Additional architectures might be supported by Debian/Ubuntu Ports.</p>
<h3 id="building-for-armaarch64">Building for ARM/aarch64</h3>
<p>A common cross-compilation target is the ARM CPU. When building for ARM, it is useful to set the ABI profile. A number of pre-defined ABI profiles are available using <code>--with-abi-profile</code>: arm-vfp-sflt, arm-vfp-hflt, arm-sflt, armv5-vfp-sflt, armv6-vfp-hflt. Note that soft-float ABIs are no longer properly supported by the JDK.</p>
<p>The JDK contains two different ports for the aarch64 platform, one is the original aarch64 port from the <a href="http://openjdk.java.net/projects/aarch64-port">AArch64 Port Project</a> and one is a 64-bit version of the Oracle contributed ARM port. When targeting aarch64, by the default the original aarch64 port is used. To select the Oracle ARM 64 port, use <code>--with-cpu-port=arm64</code>. Also set the corresponding value (<code>aarch64</code> or <code>arm64</code>) to --with-abi-profile, to ensure a consistent build.</p>
--- a/doc/building.md Mon Aug 27 16:01:38 2018 -0400
+++ b/doc/building.md Mon Aug 27 16:02:55 2018 -0400
@@ -1018,6 +1018,51 @@
* If the X11 libraries are not properly detected by `configure`, you can
point them out by `--with-x`.
+### Creating And Using Sysroots With qemu-deboostrap
+
+Fortunately, you can create sysroots for foreign architectures with tools
+provided by your OS. On Debian/Ubuntu systems, one could use `qemu-deboostrap` to
+create the *target* system chroot, which would have the native libraries and headers
+specific to that *target* system. After that, we can use the cross-compiler on the *build*
+system, pointing into chroot to get the build dependencies right. This allows building
+for foreign architectures with native compilation speed.
+
+For example, cross-compiling to AArch64 from x86_64 could be done like this:
+
+ * Install cross-compiler on the *build* system:
+```
+apt install g++-aarch64-linux-gnu gcc-aarch64-linux-gnu
+```
+
+ * Create chroot on the *build* system, configuring it for *target* system:
+```
+sudo qemu-debootstrap --arch=arm64 --verbose \
+ --include=fakeroot,build-essential,libx11-dev,libxext-dev,libxrender-dev,libxtst-dev,libxt-dev,libcups2-dev,libfontconfig1-dev,libasound2-dev,libfreetype6-dev,libpng12-dev \
+ --resolve-deps jessie /chroots/arm64 http://httpredir.debian.org/debian/
+```
+
+ * Configure and build with newly created chroot as sysroot/toolchain-path:
+```
+CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++ sh ./configure --openjdk-target=aarch64-linux-gnu --with-sysroot=/chroots/arm64/ --with-toolchain-path=/chroots/arm64/
+make images
+ls build/linux-aarch64-normal-server-release/
+```
+
+The build does not create new files in that chroot, so it can be reused for multiple builds
+without additional cleanup.
+
+Architectures that are known to successfully cross-compile like this are:
+
+ Target `CC` `CXX` `--arch=...` `--openjdk-target=...`
+ ------------ ------------------------- --------------------------- ------------ ----------------------
+ x86 default default i386 i386-linux-gnu
+ armhf gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf armhf arm-linux-gnueabihf
+ aarch64 gcc-aarch64-linux-gnu g++-aarch64-linux-gnu arm64 aarch64-linux-gnu
+ ppc64el gcc-powerpc64le-linux-gnu g++-powerpc64le-linux-gnu ppc64el powerpc64le-linux-gnu
+ s390x gcc-s390x-linux-gnu g++-s390x-linux-gnu s390x s390x-linux-gnu
+
+Additional architectures might be supported by Debian/Ubuntu Ports.
+
### Building for ARM/aarch64
A common cross-compilation target is the ARM CPU. When building for ARM, it is
--- a/make/common/TestFilesCompilation.gmk Mon Aug 27 16:01:38 2018 -0400
+++ b/make/common/TestFilesCompilation.gmk Mon Aug 27 16:02:55 2018 -0400
@@ -94,7 +94,7 @@
CFLAGS := $$($1_CFLAGS) $$($1_CFLAGS_$$(name)), \
LDFLAGS := $$($1_LDFLAGS) $$($1_LDFLAGS_$$(name)), \
LIBS := $$($1_LIBS_$$(name)), \
- OPTIMIZATION := LOW, \
+ OPTIMIZATION := $$(if $$($1_OPTIMIZATION_$$(name)),$$($1_OPTIMIZATION_$$(name)),LOW), \
COPY_DEBUG_SYMBOLS := false, \
STRIP_SYMBOLS := false, \
)) \
--- a/make/test/JtregNativeHotspot.gmk Mon Aug 27 16:01:38 2018 -0400
+++ b/make/test/JtregNativeHotspot.gmk Mon Aug 27 16:02:55 2018 -0400
@@ -139,6 +139,15 @@
-I$(VM_TESTBASE_DIR)/nsk/share/native \
-I$(VM_TESTBASE_DIR)/nsk/share/jni
+NO_FRAMEPOINTER_CFLAGS :=
+ifeq ($(OPENJDK_TARGET_OS),linux)
+ NO_FRAMEPOINTER_CFLAGS := -fomit-frame-pointer
+endif
+
+BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libNoFramePointer := $(NO_FRAMEPOINTER_CFLAGS)
+# Optimization -O3 needed, HIGH == -O3
+BUILD_HOTSPOT_JTREG_LIBRARIES_OPTIMIZATION_libNoFramePointer := HIGH
+
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libProcessUtils := $(VM_SHARE_INCLUDES)
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libThreadController := $(NSK_MONITORING_INCLUDES)
--- a/src/hotspot/share/c1/c1_LIRAssembler.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -112,6 +112,9 @@
LIR_Assembler::~LIR_Assembler() {
+ // The unwind handler label may be unnbound if this destructor is invoked because of a bail-out.
+ // Reset it here to avoid an assertion.
+ _unwind_handler_entry.reset();
}
--- a/src/hotspot/share/c1/c1_LIRAssembler.hpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/c1/c1_LIRAssembler.hpp Mon Aug 27 16:02:55 2018 -0400
@@ -71,11 +71,7 @@
void record_non_safepoint_debug_info();
// unified bailout support
- void bailout(const char* msg) {
- // reset the label in case it hits assertion in destructor.
- _unwind_handler_entry.reset();
- compilation()->bailout(msg);
- }
+ void bailout(const char* msg) const { compilation()->bailout(msg); }
bool bailed_out() const { return compilation()->bailed_out(); }
// code emission patterns and accessors
--- a/src/hotspot/share/classfile/classLoaderData.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/classfile/classLoaderData.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -655,7 +655,7 @@
size = _default_loader_dictionary_size;
resizable = true;
}
- if (!DynamicallyResizeSystemDictionaries || DumpSharedSpaces || UseSharedSpaces) {
+ if (!DynamicallyResizeSystemDictionaries || DumpSharedSpaces) {
resizable = false;
}
return new Dictionary(this, size, resizable);
@@ -1254,15 +1254,6 @@
}
}
-// Walks all entries in the dictionary including entries initiated by this class loader.
-void ClassLoaderDataGraph::dictionary_all_entries_do(void f(InstanceKlass*, ClassLoaderData*)) {
- Thread* thread = Thread::current();
- FOR_ALL_DICTIONARY(cld) {
- Handle holder(thread, cld->holder_phantom());
- cld->dictionary()->all_entries_do(f);
- }
-}
-
void ClassLoaderDataGraph::verify_dictionary() {
FOR_ALL_DICTIONARY(cld) {
cld->dictionary()->verify();
--- a/src/hotspot/share/classfile/classLoaderData.hpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/classfile/classLoaderData.hpp Mon Aug 27 16:02:55 2018 -0400
@@ -134,9 +134,6 @@
// Added for initialize_itable_for_klass to handle exceptions.
static void dictionary_classes_do(void f(InstanceKlass*, TRAPS), TRAPS);
- // Iterate all classes and their class loaders, including initiating class loaders.
- static void dictionary_all_entries_do(void f(InstanceKlass*, ClassLoaderData*));
-
// VM_CounterDecay iteration support
static InstanceKlass* try_get_next_class();
--- a/src/hotspot/share/classfile/dictionary.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/classfile/dictionary.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -330,13 +330,13 @@
}
// All classes, and their class loaders, including initiating class loaders
-void Dictionary::all_entries_do(void f(InstanceKlass*, ClassLoaderData*)) {
+void Dictionary::all_entries_do(KlassClosure* closure) {
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
InstanceKlass* k = probe->instance_klass();
- f(k, loader_data());
+ closure->do_klass(k);
}
}
}
@@ -592,8 +592,8 @@
ResourceMark rm;
assert(loader_data() != NULL, "loader data should not be null");
- st->print_cr("Java dictionary (table_size=%d, classes=%d)",
- table_size(), number_of_entries());
+ st->print_cr("Java dictionary (table_size=%d, classes=%d, resizable=%s)",
+ table_size(), number_of_entries(), BOOL_TO_STR(_resizable));
st->print_cr("^ indicates that initiating loader is different from defining loader");
for (int index = 0; index < table_size(); index++) {
--- a/src/hotspot/share/classfile/dictionary.hpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/classfile/dictionary.hpp Mon Aug 27 16:02:55 2018 -0400
@@ -74,7 +74,7 @@
void classes_do(void f(InstanceKlass*));
void classes_do(void f(InstanceKlass*, TRAPS), TRAPS);
- void all_entries_do(void f(InstanceKlass*, ClassLoaderData*));
+ void all_entries_do(KlassClosure* closure);
void classes_do(MetaspaceClosure* it);
void unlink();
--- a/src/hotspot/share/classfile/javaClasses.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/classfile/javaClasses.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -1271,6 +1271,13 @@
return size;
}
+int java_lang_Class::oop_size_raw(oop java_class) {
+ assert(_oop_size_offset != 0, "must be set");
+ int size = java_class->int_field_raw(_oop_size_offset);
+ assert(size > 0, "Oop size must be greater than zero, not %d", size);
+ return size;
+}
+
void java_lang_Class::set_oop_size(HeapWord* java_class, int size) {
assert(_oop_size_offset != 0, "must be set");
assert(size > 0, "Oop size must be greater than zero, not %d", size);
@@ -1281,6 +1288,12 @@
assert(_static_oop_field_count_offset != 0, "must be set");
return java_class->int_field(_static_oop_field_count_offset);
}
+
+int java_lang_Class::static_oop_field_count_raw(oop java_class) {
+ assert(_static_oop_field_count_offset != 0, "must be set");
+ return java_class->int_field_raw(_static_oop_field_count_offset);
+}
+
void java_lang_Class::set_static_oop_field_count(oop java_class, int size) {
assert(_static_oop_field_count_offset != 0, "must be set");
java_class->int_field_put(_static_oop_field_count_offset, size);
@@ -1370,6 +1383,14 @@
return k;
}
+Klass* java_lang_Class::as_Klass_raw(oop java_class) {
+ //%note memory_2
+ assert(java_lang_Class::is_instance(java_class), "must be a Class object");
+ Klass* k = ((Klass*)java_class->metadata_field_raw(_klass_offset));
+ assert(k == NULL || k->is_klass(), "type check");
+ return k;
+}
+
void java_lang_Class::set_klass(oop java_class, Klass* klass) {
assert(java_lang_Class::is_instance(java_class), "must be a Class object");
@@ -4007,6 +4028,11 @@
return HeapAccess<>::load_at(loader, _loader_data_offset);
}
+ClassLoaderData* java_lang_ClassLoader::loader_data_raw(oop loader) {
+ assert(loader != NULL && oopDesc::is_oop(loader), "loader must be oop");
+ return RawAccess<>::load_at(loader, _loader_data_offset);
+}
+
ClassLoaderData* java_lang_ClassLoader::cmpxchg_loader_data(ClassLoaderData* new_data, oop loader, ClassLoaderData* expected_data) {
assert(loader != NULL && oopDesc::is_oop(loader), "loader must be oop");
return HeapAccess<>::atomic_cmpxchg_at(new_data, loader, _loader_data_offset, expected_data);
--- a/src/hotspot/share/classfile/javaClasses.hpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/classfile/javaClasses.hpp Mon Aug 27 16:02:55 2018 -0400
@@ -277,6 +277,7 @@
// Conversion
static Klass* as_Klass(oop java_class);
+ static Klass* as_Klass_raw(oop java_class);
static void set_klass(oop java_class, Klass* klass);
static BasicType as_BasicType(oop java_class, Klass** reference_klass = NULL);
static Symbol* as_signature(oop java_class, bool intern_if_not_found, TRAPS);
@@ -310,8 +311,10 @@
static oop module(oop java_class);
static int oop_size(oop java_class);
+ static int oop_size_raw(oop java_class);
static void set_oop_size(HeapWord* java_class, int size);
static int static_oop_field_count(oop java_class);
+ static int static_oop_field_count_raw(oop java_class);
static void set_static_oop_field_count(oop java_class, int size);
static GrowableArray<Klass*>* fixup_mirror_list() {
@@ -1320,6 +1323,7 @@
static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
static ClassLoaderData* loader_data(oop loader);
+ static ClassLoaderData* loader_data_raw(oop loader);
static ClassLoaderData* cmpxchg_loader_data(ClassLoaderData* new_data, oop loader, ClassLoaderData* expected_data);
static oop parent(oop loader);
--- a/src/hotspot/share/classfile/symbolTable.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/classfile/symbolTable.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -134,7 +134,7 @@
void SymbolTable::delete_symbol(Symbol* sym) {
if (sym->refcount() == PERM_REFCOUNT) {
- MutexLocker ml(SymbolTable_lock); // Protect arena
+ MutexLockerEx ml(SymbolArena_lock, Mutex::_no_safepoint_check_flag); // Protect arena
// Deleting permanent symbol should not occur very often (insert race condition),
// so log it.
log_trace_symboltable_helper(sym, "Freeing permanent symbol");
@@ -197,7 +197,7 @@
assert(sym != NULL, "new should call vm_exit_out_of_memory if C_HEAP is exhausted");
} else {
// Allocate to global arena
- MutexLocker ml(SymbolTable_lock); // Protect arena
+ MutexLockerEx ml(SymbolArena_lock, Mutex::_no_safepoint_check_flag); // Protect arena
sym = new (len, arena(), THREAD) Symbol((const u1*)name, len, PERM_REFCOUNT);
}
return sym;
--- a/src/hotspot/share/classfile/systemDictionary.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/classfile/systemDictionary.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -1160,10 +1160,12 @@
#if INCLUDE_CDS
void SystemDictionary::set_shared_dictionary(HashtableBucket<mtClass>* t, int length,
int number_of_entries) {
+ assert(!DumpSharedSpaces, "Should not be called with DumpSharedSpaces");
assert(length == _shared_dictionary_size * sizeof(HashtableBucket<mtClass>),
"bad shared dictionary size.");
_shared_dictionary = new Dictionary(ClassLoaderData::the_null_class_loader_data(),
- _shared_dictionary_size, t, number_of_entries);
+ _shared_dictionary_size, t, number_of_entries,
+ false /* explicitly set _resizable to false */);
}
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -70,6 +70,7 @@
#include "gc/shared/generationSpec.hpp"
#include "gc/shared/isGCActiveMark.hpp"
#include "gc/shared/oopStorageParState.hpp"
+#include "gc/shared/parallelCleaning.hpp"
#include "gc/shared/preservedMarks.inline.hpp"
#include "gc/shared/suspendibleThreadSet.hpp"
#include "gc/shared/referenceProcessor.inline.hpp"
@@ -3298,334 +3299,12 @@
undo_waste * HeapWordSize / K);
}
-class G1StringCleaningTask : public AbstractGangTask {
-private:
- BoolObjectClosure* _is_alive;
- G1StringDedupUnlinkOrOopsDoClosure _dedup_closure;
- OopStorage::ParState<false /* concurrent */, false /* const */> _par_state_string;
-
- int _initial_string_table_size;
-
- bool _process_strings;
- int _strings_processed;
- int _strings_removed;
-
- bool _process_string_dedup;
-
-public:
- G1StringCleaningTask(BoolObjectClosure* is_alive, bool process_strings, bool process_string_dedup) :
- AbstractGangTask("String Unlinking"),
- _is_alive(is_alive),
- _dedup_closure(is_alive, NULL, false),
- _par_state_string(StringTable::weak_storage()),
- _process_strings(process_strings), _strings_processed(0), _strings_removed(0),
- _process_string_dedup(process_string_dedup) {
-
- _initial_string_table_size = (int) StringTable::the_table()->table_size();
- if (process_strings) {
- StringTable::reset_dead_counter();
- }
- }
-
- ~G1StringCleaningTask() {
- log_info(gc, stringtable)(
- "Cleaned string table, "
- "strings: " SIZE_FORMAT " processed, " SIZE_FORMAT " removed",
- strings_processed(), strings_removed());
- if (_process_strings) {
- StringTable::finish_dead_counter();
- }
- }
-
- void work(uint worker_id) {
- int strings_processed = 0;
- int strings_removed = 0;
- if (_process_strings) {
- StringTable::possibly_parallel_unlink(&_par_state_string, _is_alive, &strings_processed, &strings_removed);
- Atomic::add(strings_processed, &_strings_processed);
- Atomic::add(strings_removed, &_strings_removed);
- }
- if (_process_string_dedup) {
- G1StringDedup::parallel_unlink(&_dedup_closure, worker_id);
- }
- }
-
- size_t strings_processed() const { return (size_t)_strings_processed; }
- size_t strings_removed() const { return (size_t)_strings_removed; }
-};
-
-class G1CodeCacheUnloadingTask {
-private:
- static Monitor* _lock;
-
- BoolObjectClosure* const _is_alive;
- const bool _unloading_occurred;
- const uint _num_workers;
-
- // Variables used to claim nmethods.
- CompiledMethod* _first_nmethod;
- CompiledMethod* volatile _claimed_nmethod;
-
- // The list of nmethods that need to be processed by the second pass.
- CompiledMethod* volatile _postponed_list;
- volatile uint _num_entered_barrier;
-
- public:
- G1CodeCacheUnloadingTask(uint num_workers, BoolObjectClosure* is_alive, bool unloading_occurred) :
- _is_alive(is_alive),
- _unloading_occurred(unloading_occurred),
- _num_workers(num_workers),
- _first_nmethod(NULL),
- _claimed_nmethod(NULL),
- _postponed_list(NULL),
- _num_entered_barrier(0)
- {
- CompiledMethod::increase_unloading_clock();
- // Get first alive nmethod
- CompiledMethodIterator iter = CompiledMethodIterator();
- if(iter.next_alive()) {
- _first_nmethod = iter.method();
- }
- _claimed_nmethod = _first_nmethod;
- }
-
- ~G1CodeCacheUnloadingTask() {
- CodeCache::verify_clean_inline_caches();
-
- CodeCache::set_needs_cache_clean(false);
- guarantee(CodeCache::scavenge_root_nmethods() == NULL, "Must be");
-
- CodeCache::verify_icholder_relocations();
- }
-
- private:
- void add_to_postponed_list(CompiledMethod* nm) {
- CompiledMethod* old;
- do {
- old = _postponed_list;
- nm->set_unloading_next(old);
- } while (Atomic::cmpxchg(nm, &_postponed_list, old) != old);
- }
-
- void clean_nmethod(CompiledMethod* nm) {
- bool postponed = nm->do_unloading_parallel(_is_alive, _unloading_occurred);
-
- if (postponed) {
- // This nmethod referred to an nmethod that has not been cleaned/unloaded yet.
- add_to_postponed_list(nm);
- }
-
- // Mark that this nmethod has been cleaned/unloaded.
- // After this call, it will be safe to ask if this nmethod was unloaded or not.
- nm->set_unloading_clock(CompiledMethod::global_unloading_clock());
- }
-
- void clean_nmethod_postponed(CompiledMethod* nm) {
- nm->do_unloading_parallel_postponed();
- }
-
- static const int MaxClaimNmethods = 16;
-
- void claim_nmethods(CompiledMethod** claimed_nmethods, int *num_claimed_nmethods) {
- CompiledMethod* first;
- CompiledMethodIterator last;
-
- do {
- *num_claimed_nmethods = 0;
-
- first = _claimed_nmethod;
- last = CompiledMethodIterator(first);
-
- if (first != NULL) {
-
- for (int i = 0; i < MaxClaimNmethods; i++) {
- if (!last.next_alive()) {
- break;
- }
- claimed_nmethods[i] = last.method();
- (*num_claimed_nmethods)++;
- }
- }
-
- } while (Atomic::cmpxchg(last.method(), &_claimed_nmethod, first) != first);
- }
-
- CompiledMethod* claim_postponed_nmethod() {
- CompiledMethod* claim;
- CompiledMethod* next;
-
- do {
- claim = _postponed_list;
- if (claim == NULL) {
- return NULL;
- }
-
- next = claim->unloading_next();
-
- } while (Atomic::cmpxchg(next, &_postponed_list, claim) != claim);
-
- return claim;
- }
-
- public:
- // Mark that we're done with the first pass of nmethod cleaning.
- void barrier_mark(uint worker_id) {
- MonitorLockerEx ml(_lock, Mutex::_no_safepoint_check_flag);
- _num_entered_barrier++;
- if (_num_entered_barrier == _num_workers) {
- ml.notify_all();
- }
- }
-
- // See if we have to wait for the other workers to
- // finish their first-pass nmethod cleaning work.
- void barrier_wait(uint worker_id) {
- if (_num_entered_barrier < _num_workers) {
- MonitorLockerEx ml(_lock, Mutex::_no_safepoint_check_flag);
- while (_num_entered_barrier < _num_workers) {
- ml.wait(Mutex::_no_safepoint_check_flag, 0, false);
- }
- }
- }
-
- // Cleaning and unloading of nmethods. Some work has to be postponed
- // to the second pass, when we know which nmethods survive.
- void work_first_pass(uint worker_id) {
- // The first nmethods is claimed by the first worker.
- if (worker_id == 0 && _first_nmethod != NULL) {
- clean_nmethod(_first_nmethod);
- _first_nmethod = NULL;
- }
-
- int num_claimed_nmethods;
- CompiledMethod* claimed_nmethods[MaxClaimNmethods];
-
- while (true) {
- claim_nmethods(claimed_nmethods, &num_claimed_nmethods);
-
- if (num_claimed_nmethods == 0) {
- break;
- }
-
- for (int i = 0; i < num_claimed_nmethods; i++) {
- clean_nmethod(claimed_nmethods[i]);
- }
- }
- }
-
- void work_second_pass(uint worker_id) {
- CompiledMethod* nm;
- // Take care of postponed nmethods.
- while ((nm = claim_postponed_nmethod()) != NULL) {
- clean_nmethod_postponed(nm);
- }
- }
-};
-
-Monitor* G1CodeCacheUnloadingTask::_lock = new Monitor(Mutex::leaf, "Code Cache Unload lock", false, Monitor::_safepoint_check_never);
-
-class G1KlassCleaningTask : public StackObj {
- volatile int _clean_klass_tree_claimed;
- ClassLoaderDataGraphKlassIteratorAtomic _klass_iterator;
-
- public:
- G1KlassCleaningTask() :
- _clean_klass_tree_claimed(0),
- _klass_iterator() {
- }
-
- private:
- bool claim_clean_klass_tree_task() {
- if (_clean_klass_tree_claimed) {
- return false;
- }
-
- return Atomic::cmpxchg(1, &_clean_klass_tree_claimed, 0) == 0;
- }
-
- InstanceKlass* claim_next_klass() {
- Klass* klass;
- do {
- klass =_klass_iterator.next_klass();
- } while (klass != NULL && !klass->is_instance_klass());
-
- // this can be null so don't call InstanceKlass::cast
- return static_cast<InstanceKlass*>(klass);
- }
-
-public:
-
- void clean_klass(InstanceKlass* ik) {
- ik->clean_weak_instanceklass_links();
- }
-
- void work() {
- ResourceMark rm;
-
- // One worker will clean the subklass/sibling klass tree.
- if (claim_clean_klass_tree_task()) {
- Klass::clean_subklass_tree();
- }
-
- // All workers will help cleaning the classes,
- InstanceKlass* klass;
- while ((klass = claim_next_klass()) != NULL) {
- clean_klass(klass);
- }
- }
-};
-
-// To minimize the remark pause times, the tasks below are done in parallel.
-class G1ParallelCleaningTask : public AbstractGangTask {
-private:
- bool _unloading_occurred;
- G1StringCleaningTask _string_task;
- G1CodeCacheUnloadingTask _code_cache_task;
- G1KlassCleaningTask _klass_cleaning_task;
-
-public:
- // The constructor is run in the VMThread.
- G1ParallelCleaningTask(BoolObjectClosure* is_alive, uint num_workers, bool unloading_occurred) :
- AbstractGangTask("Parallel Cleaning"),
- _unloading_occurred(unloading_occurred),
- _string_task(is_alive, true, G1StringDedup::is_enabled()),
- _code_cache_task(num_workers, is_alive, unloading_occurred),
- _klass_cleaning_task() {
- }
-
- // The parallel work done by all worker threads.
- void work(uint worker_id) {
- // Do first pass of code cache cleaning.
- _code_cache_task.work_first_pass(worker_id);
-
- // Let the threads mark that the first pass is done.
- _code_cache_task.barrier_mark(worker_id);
-
- // Clean the Strings.
- _string_task.work(worker_id);
-
- // Wait for all workers to finish the first code cache cleaning pass.
- _code_cache_task.barrier_wait(worker_id);
-
- // Do the second code cache cleaning work, which realize on
- // the liveness information gathered during the first pass.
- _code_cache_task.work_second_pass(worker_id);
-
- // Clean all klasses that were not unloaded.
- // The weak metadata in klass doesn't need to be
- // processed if there was no unloading.
- if (_unloading_occurred) {
- _klass_cleaning_task.work();
- }
- }
-};
-
-
void G1CollectedHeap::complete_cleaning(BoolObjectClosure* is_alive,
bool class_unloading_occurred) {
uint n_workers = workers()->active_workers();
- G1ParallelCleaningTask g1_unlink_task(is_alive, n_workers, class_unloading_occurred);
+ G1StringDedupUnlinkOrOopsDoClosure dedup_closure(is_alive, NULL, false);
+ ParallelCleaningTask g1_unlink_task(is_alive, &dedup_closure, n_workers, class_unloading_occurred);
workers()->run_task(&g1_unlink_task);
}
@@ -3637,7 +3316,8 @@
return;
}
- G1StringCleaningTask g1_unlink_task(is_alive, process_strings, process_string_dedup);
+ G1StringDedupUnlinkOrOopsDoClosure dedup_closure(is_alive, NULL, false);
+ StringCleaningTask g1_unlink_task(is_alive, process_string_dedup ? &dedup_closure : NULL, process_strings);
workers()->run_task(&g1_unlink_task);
}
--- a/src/hotspot/share/gc/shared/oopStorage.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/gc/shared/oopStorage.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -43,7 +43,6 @@
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
-#include "utilities/spinYield.hpp"
OopStorage::AllocationListEntry::AllocationListEntry() : _prev(NULL), _next(NULL) {}
@@ -495,48 +494,6 @@
return true;
}
-OopStorage::ProtectActive::ProtectActive() : _enter(0), _exit() {}
-
-// Begin read-side critical section.
-uint OopStorage::ProtectActive::read_enter() {
- return Atomic::add(2u, &_enter);
-}
-
-// End read-side critical section.
-void OopStorage::ProtectActive::read_exit(uint enter_value) {
- Atomic::add(2u, &_exit[enter_value & 1]);
-}
-
-// Wait until all readers that entered the critical section before
-// synchronization have exited that critical section.
-void OopStorage::ProtectActive::write_synchronize() {
- SpinYield spinner;
- // Determine old and new exit counters, based on bit0 of the
- // on-entry _enter counter.
- uint value = OrderAccess::load_acquire(&_enter);
- volatile uint* new_ptr = &_exit[(value + 1) & 1];
- // Atomically change the in-use exit counter to the new counter, by
- // adding 1 to the _enter counter (flipping bit0 between 0 and 1)
- // and initializing the new exit counter to that enter value. Note:
- // The new exit counter is not being used by read operations until
- // this change succeeds.
- uint old;
- do {
- old = value;
- *new_ptr = ++value;
- value = Atomic::cmpxchg(value, &_enter, old);
- } while (old != value);
- // Readers that entered the critical section before we changed the
- // selected exit counter will use the old exit counter. Readers
- // entering after the change will use the new exit counter. Wait
- // for all the critical sections started before the change to
- // complete, e.g. for the value of old_ptr to catch up with old.
- volatile uint* old_ptr = &_exit[old & 1];
- while (old != OrderAccess::load_acquire(old_ptr)) {
- spinner.wait();
- }
-}
-
// Make new_array the _active_array. Increments new_array's refcount
// to account for the new reference. The assignment is atomic wrto
// obtain_active_array; once this function returns, it is safe for the
@@ -548,7 +505,10 @@
// Install new_array, ensuring its initialization is complete first.
OrderAccess::release_store(&_active_array, new_array);
// Wait for any readers that could read the old array from _active_array.
- _protect_active.write_synchronize();
+ // Can't use GlobalCounter here, because this is called from allocate(),
+ // which may be called in the scope of a GlobalCounter critical section
+ // when inserting a StringTable entry.
+ _protect_active.synchronize();
// All obtain critical sections that could see the old array have
// completed, having incremented the refcount of the old array. The
// caller can now safely relinquish the old array.
@@ -560,10 +520,9 @@
// _active_array. The caller must relinquish the array when done
// using it.
OopStorage::ActiveArray* OopStorage::obtain_active_array() const {
- uint enter_value = _protect_active.read_enter();
+ SingleWriterSynchronizer::CriticalSection cs(&_protect_active);
ActiveArray* result = OrderAccess::load_acquire(&_active_array);
result->increment_refcount();
- _protect_active.read_exit(enter_value);
return result;
}
--- a/src/hotspot/share/gc/shared/oopStorage.hpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/gc/shared/oopStorage.hpp Mon Aug 27 16:02:55 2018 -0400
@@ -29,6 +29,7 @@
#include "oops/oop.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
+#include "utilities/singleWriterSynchronizer.hpp"
class Mutex;
class outputStream;
@@ -203,19 +204,6 @@
void unlink(const Block& block);
};
- // RCU-inspired protection of access to _active_array.
- class ProtectActive {
- volatile uint _enter;
- volatile uint _exit[2];
-
- public:
- ProtectActive();
-
- uint read_enter();
- void read_exit(uint enter_value);
- void write_synchronize();
- };
-
private:
const char* _name;
ActiveArray* _active_array;
@@ -229,7 +217,7 @@
volatile size_t _allocation_count;
// Protection for _active_array.
- mutable ProtectActive _protect_active;
+ mutable SingleWriterSynchronizer _protect_active;
// mutable because this gets set even for const iteration.
mutable bool _concurrent_iteration_active;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/parallelCleaning.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -0,0 +1,282 @@
+/*
+ * 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/symbolTable.hpp"
+#include "classfile/stringTable.hpp"
+#include "code/codeCache.hpp"
+#include "gc/shared/parallelCleaning.hpp"
+#include "memory/resourceArea.hpp"
+#include "logging/log.hpp"
+
+StringCleaningTask::StringCleaningTask(BoolObjectClosure* is_alive, StringDedupUnlinkOrOopsDoClosure* dedup_closure, bool process_strings) :
+ AbstractGangTask("String Unlinking"),
+ _is_alive(is_alive),
+ _dedup_closure(dedup_closure),
+ _par_state_string(StringTable::weak_storage()),
+ _initial_string_table_size((int) StringTable::the_table()->table_size()),
+ _process_strings(process_strings), _strings_processed(0), _strings_removed(0) {
+
+ if (process_strings) {
+ StringTable::reset_dead_counter();
+ }
+}
+
+StringCleaningTask::~StringCleaningTask() {
+ log_info(gc, stringtable)(
+ "Cleaned string table, "
+ "strings: " SIZE_FORMAT " processed, " SIZE_FORMAT " removed",
+ strings_processed(), strings_removed());
+ if (_process_strings) {
+ StringTable::finish_dead_counter();
+ }
+}
+
+void StringCleaningTask::work(uint worker_id) {
+ int strings_processed = 0;
+ int strings_removed = 0;
+ if (_process_strings) {
+ StringTable::possibly_parallel_unlink(&_par_state_string, _is_alive, &strings_processed, &strings_removed);
+ Atomic::add(strings_processed, &_strings_processed);
+ Atomic::add(strings_removed, &_strings_removed);
+ }
+ if (_dedup_closure != NULL) {
+ StringDedup::parallel_unlink(_dedup_closure, worker_id);
+ }
+}
+
+CodeCacheUnloadingTask::CodeCacheUnloadingTask(uint num_workers, BoolObjectClosure* is_alive, bool unloading_occurred) :
+ _is_alive(is_alive),
+ _unloading_occurred(unloading_occurred),
+ _num_workers(num_workers),
+ _first_nmethod(NULL),
+ _claimed_nmethod(NULL),
+ _postponed_list(NULL),
+ _num_entered_barrier(0) {
+ CompiledMethod::increase_unloading_clock();
+ // Get first alive nmethod
+ CompiledMethodIterator iter = CompiledMethodIterator();
+ if(iter.next_alive()) {
+ _first_nmethod = iter.method();
+ }
+ _claimed_nmethod = _first_nmethod;
+}
+
+CodeCacheUnloadingTask::~CodeCacheUnloadingTask() {
+ CodeCache::verify_clean_inline_caches();
+
+ CodeCache::set_needs_cache_clean(false);
+ guarantee(CodeCache::scavenge_root_nmethods() == NULL, "Must be");
+
+ CodeCache::verify_icholder_relocations();
+}
+
+Monitor* CodeCacheUnloadingTask::_lock = new Monitor(Mutex::leaf, "Code Cache Unload lock", false, Monitor::_safepoint_check_never);
+
+void CodeCacheUnloadingTask::add_to_postponed_list(CompiledMethod* nm) {
+ CompiledMethod* old;
+ do {
+ old = _postponed_list;
+ nm->set_unloading_next(old);
+ } while (Atomic::cmpxchg(nm, &_postponed_list, old) != old);
+}
+
+void CodeCacheUnloadingTask::clean_nmethod(CompiledMethod* nm) {
+ bool postponed = nm->do_unloading_parallel(_is_alive, _unloading_occurred);
+
+ if (postponed) {
+ // This nmethod referred to an nmethod that has not been cleaned/unloaded yet.
+ add_to_postponed_list(nm);
+ }
+
+ // Mark that this nmethod has been cleaned/unloaded.
+ // After this call, it will be safe to ask if this nmethod was unloaded or not.
+ nm->set_unloading_clock(CompiledMethod::global_unloading_clock());
+}
+
+void CodeCacheUnloadingTask::clean_nmethod_postponed(CompiledMethod* nm) {
+ nm->do_unloading_parallel_postponed();
+}
+
+void CodeCacheUnloadingTask::claim_nmethods(CompiledMethod** claimed_nmethods, int *num_claimed_nmethods) {
+ CompiledMethod* first;
+ CompiledMethodIterator last;
+
+ do {
+ *num_claimed_nmethods = 0;
+
+ first = _claimed_nmethod;
+ last = CompiledMethodIterator(first);
+
+ if (first != NULL) {
+
+ for (int i = 0; i < MaxClaimNmethods; i++) {
+ if (!last.next_alive()) {
+ break;
+ }
+ claimed_nmethods[i] = last.method();
+ (*num_claimed_nmethods)++;
+ }
+ }
+
+ } while (Atomic::cmpxchg(last.method(), &_claimed_nmethod, first) != first);
+}
+
+CompiledMethod* CodeCacheUnloadingTask::claim_postponed_nmethod() {
+ CompiledMethod* claim;
+ CompiledMethod* next;
+
+ do {
+ claim = _postponed_list;
+ if (claim == NULL) {
+ return NULL;
+ }
+
+ next = claim->unloading_next();
+
+ } while (Atomic::cmpxchg(next, &_postponed_list, claim) != claim);
+
+ return claim;
+}
+
+void CodeCacheUnloadingTask::barrier_mark(uint worker_id) {
+ MonitorLockerEx ml(_lock, Mutex::_no_safepoint_check_flag);
+ _num_entered_barrier++;
+ if (_num_entered_barrier == _num_workers) {
+ ml.notify_all();
+ }
+}
+
+void CodeCacheUnloadingTask::barrier_wait(uint worker_id) {
+ if (_num_entered_barrier < _num_workers) {
+ MonitorLockerEx ml(_lock, Mutex::_no_safepoint_check_flag);
+ while (_num_entered_barrier < _num_workers) {
+ ml.wait(Mutex::_no_safepoint_check_flag, 0, false);
+ }
+ }
+}
+
+void CodeCacheUnloadingTask::work_first_pass(uint worker_id) {
+ // The first nmethods is claimed by the first worker.
+ if (worker_id == 0 && _first_nmethod != NULL) {
+ clean_nmethod(_first_nmethod);
+ _first_nmethod = NULL;
+ }
+
+ int num_claimed_nmethods;
+ CompiledMethod* claimed_nmethods[MaxClaimNmethods];
+
+ while (true) {
+ claim_nmethods(claimed_nmethods, &num_claimed_nmethods);
+
+ if (num_claimed_nmethods == 0) {
+ break;
+ }
+
+ for (int i = 0; i < num_claimed_nmethods; i++) {
+ clean_nmethod(claimed_nmethods[i]);
+ }
+ }
+}
+
+void CodeCacheUnloadingTask::work_second_pass(uint worker_id) {
+ CompiledMethod* nm;
+ // Take care of postponed nmethods.
+ while ((nm = claim_postponed_nmethod()) != NULL) {
+ clean_nmethod_postponed(nm);
+ }
+}
+
+KlassCleaningTask::KlassCleaningTask() :
+ _clean_klass_tree_claimed(0),
+ _klass_iterator() {
+}
+
+bool KlassCleaningTask::claim_clean_klass_tree_task() {
+ if (_clean_klass_tree_claimed) {
+ return false;
+ }
+
+ return Atomic::cmpxchg(1, &_clean_klass_tree_claimed, 0) == 0;
+}
+
+InstanceKlass* KlassCleaningTask::claim_next_klass() {
+ Klass* klass;
+ do {
+ klass =_klass_iterator.next_klass();
+ } while (klass != NULL && !klass->is_instance_klass());
+
+ // this can be null so don't call InstanceKlass::cast
+ return static_cast<InstanceKlass*>(klass);
+}
+
+void KlassCleaningTask::work() {
+ ResourceMark rm;
+
+ // One worker will clean the subklass/sibling klass tree.
+ if (claim_clean_klass_tree_task()) {
+ Klass::clean_subklass_tree();
+ }
+
+ // All workers will help cleaning the classes,
+ InstanceKlass* klass;
+ while ((klass = claim_next_klass()) != NULL) {
+ clean_klass(klass);
+ }
+}
+
+ParallelCleaningTask::ParallelCleaningTask(BoolObjectClosure* is_alive,
+ StringDedupUnlinkOrOopsDoClosure* dedup_closure, uint num_workers, bool unloading_occurred) :
+ AbstractGangTask("Parallel Cleaning"),
+ _unloading_occurred(unloading_occurred),
+ _string_task(is_alive, StringDedup::is_enabled() ? dedup_closure : NULL, true),
+ _code_cache_task(num_workers, is_alive, unloading_occurred),
+ _klass_cleaning_task() {
+}
+
+// The parallel work done by all worker threads.
+void ParallelCleaningTask::work(uint worker_id) {
+ // Do first pass of code cache cleaning.
+ _code_cache_task.work_first_pass(worker_id);
+
+ // Let the threads mark that the first pass is done.
+ _code_cache_task.barrier_mark(worker_id);
+
+ // Clean the Strings and Symbols.
+ _string_task.work(worker_id);
+
+ // Wait for all workers to finish the first code cache cleaning pass.
+ _code_cache_task.barrier_wait(worker_id);
+
+ // Do the second code cache cleaning work, which realize on
+ // the liveness information gathered during the first pass.
+ _code_cache_task.work_second_pass(worker_id);
+
+ // Clean all klasses that were not unloaded.
+ // The weak metadata in klass doesn't need to be
+ // processed if there was no unloading.
+ if (_unloading_occurred) {
+ _klass_cleaning_task.work();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/parallelCleaning.hpp Mon Aug 27 16:02:55 2018 -0400
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_GC_SHARED_PARALLELCLEANING_HPP
+#define SHARE_VM_GC_SHARED_PARALLELCLEANING_HPP
+
+#include "gc/shared/oopStorageParState.hpp"
+#include "gc/shared/stringdedup/stringDedup.hpp"
+#include "gc/shared/workgroup.hpp"
+
+class ParallelCleaningTask;
+
+class StringCleaningTask : public AbstractGangTask {
+private:
+ BoolObjectClosure* _is_alive;
+ StringDedupUnlinkOrOopsDoClosure * const _dedup_closure;
+
+ OopStorage::ParState<false /* concurrent */, false /* const */> _par_state_string;
+
+ int _initial_string_table_size;
+
+ bool _process_strings;
+ int _strings_processed;
+ int _strings_removed;
+
+public:
+ StringCleaningTask(BoolObjectClosure* is_alive, StringDedupUnlinkOrOopsDoClosure* dedup_closure, bool process_strings);
+ ~StringCleaningTask();
+
+ void work(uint worker_id);
+
+ size_t strings_processed() const { return (size_t)_strings_processed; }
+ size_t strings_removed() const { return (size_t)_strings_removed; }
+};
+
+class CodeCacheUnloadingTask {
+private:
+ static Monitor* _lock;
+
+ BoolObjectClosure* const _is_alive;
+ const bool _unloading_occurred;
+ const uint _num_workers;
+
+ // Variables used to claim nmethods.
+ CompiledMethod* _first_nmethod;
+ CompiledMethod* volatile _claimed_nmethod;
+
+ // The list of nmethods that need to be processed by the second pass.
+ CompiledMethod* volatile _postponed_list;
+ volatile uint _num_entered_barrier;
+
+public:
+ CodeCacheUnloadingTask(uint num_workers, BoolObjectClosure* is_alive, bool unloading_occurred);
+ ~CodeCacheUnloadingTask();
+
+private:
+ void add_to_postponed_list(CompiledMethod* nm);
+ void clean_nmethod(CompiledMethod* nm);
+ void clean_nmethod_postponed(CompiledMethod* nm);
+
+ static const int MaxClaimNmethods = 16;
+
+ void claim_nmethods(CompiledMethod** claimed_nmethods, int *num_claimed_nmethods);
+ CompiledMethod* claim_postponed_nmethod();
+public:
+ // Mark that we're done with the first pass of nmethod cleaning.
+ void barrier_mark(uint worker_id);
+
+ // See if we have to wait for the other workers to
+ // finish their first-pass nmethod cleaning work.
+ void barrier_wait(uint worker_id);
+
+ // Cleaning and unloading of nmethods. Some work has to be postponed
+ // to the second pass, when we know which nmethods survive.
+ void work_first_pass(uint worker_id);
+ void work_second_pass(uint worker_id);
+};
+
+
+class KlassCleaningTask : public StackObj {
+ volatile int _clean_klass_tree_claimed;
+ ClassLoaderDataGraphKlassIteratorAtomic _klass_iterator;
+
+public:
+ KlassCleaningTask();
+
+private:
+ bool claim_clean_klass_tree_task();
+ InstanceKlass* claim_next_klass();
+
+public:
+
+ void clean_klass(InstanceKlass* ik) {
+ ik->clean_weak_instanceklass_links();
+ }
+
+ void work();
+};
+
+// To minimize the remark pause times, the tasks below are done in parallel.
+class ParallelCleaningTask : public AbstractGangTask {
+private:
+ bool _unloading_occurred;
+ StringCleaningTask _string_task;
+ CodeCacheUnloadingTask _code_cache_task;
+ KlassCleaningTask _klass_cleaning_task;
+
+public:
+ // The constructor is run in the VMThread.
+ ParallelCleaningTask(BoolObjectClosure* is_alive, StringDedupUnlinkOrOopsDoClosure* dedup_closure,
+ uint num_workers, bool unloading_occurred);
+
+ void work(uint worker_id);
+};
+
+#endif // SHARE_VM_GC_SHARED_PARALLELCLEANING_HPP
--- a/src/hotspot/share/memory/metaspace/virtualSpaceList.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/memory/metaspace/virtualSpaceList.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -1,8 +1,25 @@
/*
- * virtualSpaceList.cpp
+ * 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.
*
- * Created on: May 6, 2018
- * Author: thomas
+ * 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.
+ *
*/
--- a/src/hotspot/share/memory/universe.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/memory/universe.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -165,14 +165,15 @@
uint64_t Universe::_narrow_klass_range = (uint64_t(max_juint)+1);
void Universe::basic_type_classes_do(void f(Klass*)) {
- f(boolArrayKlassObj());
- f(byteArrayKlassObj());
- f(charArrayKlassObj());
- f(intArrayKlassObj());
- f(shortArrayKlassObj());
- f(longArrayKlassObj());
- f(singleArrayKlassObj());
- f(doubleArrayKlassObj());
+ for (int i = T_BOOLEAN; i < T_LONG+1; i++) {
+ f(_typeArrayKlassObjs[i]);
+ }
+}
+
+void Universe::basic_type_classes_do(KlassClosure *closure) {
+ for (int i = T_BOOLEAN; i < T_LONG+1; i++) {
+ closure->do_klass(_typeArrayKlassObjs[i]);
+ }
}
void Universe::oops_do(OopClosure* f, bool do_all) {
--- a/src/hotspot/share/memory/universe.hpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/memory/universe.hpp Mon Aug 27 16:02:55 2018 -0400
@@ -486,6 +486,7 @@
// Apply "f" to all klasses for basic types (classes not present in
// SystemDictionary).
static void basic_type_classes_do(void f(Klass*));
+ static void basic_type_classes_do(KlassClosure* closure);
static void metaspace_pointers_do(MetaspaceClosure* it);
// Debugging
--- a/src/hotspot/share/oops/instanceClassLoaderKlass.inline.hpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/oops/instanceClassLoaderKlass.inline.hpp Mon Aug 27 16:02:55 2018 -0400
@@ -39,7 +39,7 @@
InstanceKlass::oop_oop_iterate<T>(obj, closure);
if (Devirtualizer::do_metadata(closure)) {
- ClassLoaderData* cld = java_lang_ClassLoader::loader_data(obj);
+ ClassLoaderData* cld = java_lang_ClassLoader::loader_data_raw(obj);
// cld can be null if we have a non-registered class loader.
if (cld != NULL) {
Devirtualizer::do_cld(closure, cld);
@@ -61,7 +61,7 @@
if (Devirtualizer::do_metadata(closure)) {
if (mr.contains(obj)) {
- ClassLoaderData* cld = java_lang_ClassLoader::loader_data(obj);
+ ClassLoaderData* cld = java_lang_ClassLoader::loader_data_raw(obj);
// cld can be null if we have a non-registered class loader.
if (cld != NULL) {
Devirtualizer::do_cld(closure, cld);
--- a/src/hotspot/share/oops/instanceMirrorKlass.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/oops/instanceMirrorKlass.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -56,7 +56,7 @@
}
int InstanceMirrorKlass::oop_size(oop obj) const {
- return java_lang_Class::oop_size(obj);
+ return java_lang_Class::oop_size_raw(obj);
}
int InstanceMirrorKlass::compute_static_oop_field_count(oop obj) {
--- a/src/hotspot/share/oops/instanceMirrorKlass.inline.hpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/oops/instanceMirrorKlass.inline.hpp Mon Aug 27 16:02:55 2018 -0400
@@ -36,7 +36,7 @@
template <typename T, class OopClosureType>
void InstanceMirrorKlass::oop_oop_iterate_statics(oop obj, OopClosureType* closure) {
T* p = (T*)start_of_static_fields(obj);
- T* const end = p + java_lang_Class::static_oop_field_count(obj);
+ T* const end = p + java_lang_Class::static_oop_field_count_raw(obj);
for (; p < end; ++p) {
Devirtualizer::do_oop(closure, p);
@@ -48,7 +48,7 @@
InstanceKlass::oop_oop_iterate<T>(obj, closure);
if (Devirtualizer::do_metadata(closure)) {
- Klass* klass = java_lang_Class::as_Klass(obj);
+ Klass* klass = java_lang_Class::as_Klass_raw(obj);
// We'll get NULL for primitive mirrors.
if (klass != NULL) {
if (klass->is_instance_klass() &&
@@ -90,7 +90,7 @@
OopClosureType* closure,
MemRegion mr) {
T* p = (T*)start_of_static_fields(obj);
- T* end = p + java_lang_Class::static_oop_field_count(obj);
+ T* end = p + java_lang_Class::static_oop_field_count_raw(obj);
T* const l = (T*)mr.start();
T* const h = (T*)mr.end();
@@ -116,7 +116,7 @@
if (Devirtualizer::do_metadata(closure)) {
if (mr.contains(obj)) {
- Klass* klass = java_lang_Class::as_Klass(obj);
+ Klass* klass = java_lang_Class::as_Klass_raw(obj);
// We'll get NULL for primitive mirrors.
if (klass != NULL) {
Devirtualizer::do_klass(closure, klass);
--- a/src/hotspot/share/oops/instanceRefKlass.inline.hpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/oops/instanceRefKlass.inline.hpp Mon Aug 27 16:02:55 2018 -0400
@@ -183,8 +183,13 @@
T* discovered_addr = (T*) java_lang_ref_Reference::discovered_addr_raw(obj);
log_develop_trace(gc, ref)("InstanceRefKlass %s for obj " PTR_FORMAT, s, p2i(obj));
- log_develop_trace(gc, ref)(" referent_addr/* " PTR_FORMAT " / " PTR_FORMAT,
- p2i(referent_addr), p2i((oop)HeapAccess<ON_UNKNOWN_OOP_REF | AS_NO_KEEPALIVE>::oop_load_at(obj, java_lang_ref_Reference::referent_offset)));
+ if (java_lang_ref_Reference::is_phantom(obj)) {
+ log_develop_trace(gc, ref)(" referent_addr/* " PTR_FORMAT " / " PTR_FORMAT,
+ p2i(referent_addr), p2i((oop)HeapAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(referent_addr)));
+ } else {
+ log_develop_trace(gc, ref)(" referent_addr/* " PTR_FORMAT " / " PTR_FORMAT,
+ p2i(referent_addr), p2i((oop)HeapAccess<ON_WEAK_OOP_REF | AS_NO_KEEPALIVE>::oop_load(referent_addr)));
+ }
log_develop_trace(gc, ref)(" discovered_addr/* " PTR_FORMAT " / " PTR_FORMAT,
p2i(discovered_addr), p2i((oop)HeapAccess<AS_NO_KEEPALIVE>::oop_load(discovered_addr)));
}
--- a/src/hotspot/share/oops/oop.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/oops/oop.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -177,6 +177,7 @@
void oopDesc::release_address_field_put(int offset, address value) { HeapAccess<MO_RELEASE>::store_at(as_oop(), offset, value); }
Metadata* oopDesc::metadata_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); }
+Metadata* oopDesc::metadata_field_raw(int offset) const { return RawAccess<>::load_at(as_oop(), offset); }
void oopDesc::metadata_field_put(int offset, Metadata* value) { HeapAccess<>::store_at(as_oop(), offset, value); }
Metadata* oopDesc::metadata_field_acquire(int offset) const { return HeapAccess<MO_ACQUIRE>::load_at(as_oop(), offset); }
--- a/src/hotspot/share/oops/oop.hpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/oops/oop.hpp Mon Aug 27 16:02:55 2018 -0400
@@ -163,6 +163,7 @@
void obj_field_put_volatile(int offset, oop value);
Metadata* metadata_field(int offset) const;
+ Metadata* metadata_field_raw(int offset) const;
void metadata_field_put(int offset, Metadata* value);
Metadata* metadata_field_acquire(int offset) const;
@@ -178,6 +179,7 @@
void bool_field_put(int offset, jboolean contents);
jint int_field(int offset) const;
+ jint int_field_raw(int offset) const;
void int_field_put(int offset, jint contents);
jshort short_field(int offset) const;
--- a/src/hotspot/share/oops/oop.inline.hpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/oops/oop.inline.hpp Mon Aug 27 16:02:55 2018 -0400
@@ -306,6 +306,7 @@
inline void oopDesc::short_field_put(int offset, jshort value) { HeapAccess<>::store_at(as_oop(), offset, value); }
inline jint oopDesc::int_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); }
+inline jint oopDesc::int_field_raw(int offset) const { return RawAccess<>::load_at(as_oop(), offset); }
inline void oopDesc::int_field_put(int offset, jint value) { HeapAccess<>::store_at(as_oop(), offset, value); }
inline jlong oopDesc::long_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); }
--- a/src/hotspot/share/opto/coalesce.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/opto/coalesce.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "memory/allocation.inline.hpp"
#include "opto/block.hpp"
+#include "opto/c2compiler.hpp"
#include "opto/cfgnode.hpp"
#include "opto/chaitin.hpp"
#include "opto/coalesce.hpp"
@@ -294,9 +295,13 @@
} else {
uint ireg = m->ideal_reg();
if (ireg == 0 || ireg == Op_RegFlags) {
- assert(false, "attempted to spill a non-spillable item: %d: %s, ireg = %u, spill_type: %s",
- m->_idx, m->Name(), ireg, MachSpillCopyNode::spill_type(MachSpillCopyNode::PhiInput));
- C->record_method_not_compilable("attempted to spill a non-spillable item");
+ if (C->subsume_loads()) {
+ C->record_failure(C2Compiler::retry_no_subsuming_loads());
+ } else {
+ assert(false, "attempted to spill a non-spillable item: %d: %s, ireg = %u, spill_type: %s",
+ m->_idx, m->Name(), ireg, MachSpillCopyNode::spill_type(MachSpillCopyNode::PhiInput));
+ C->record_method_not_compilable("attempted to spill a non-spillable item");
+ }
return;
}
const RegMask *rm = C->matcher()->idealreg2spillmask[ireg];
--- a/src/hotspot/share/opto/graphKit.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/opto/graphKit.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -1772,7 +1772,7 @@
//return xcall; // no need, caller already has it
}
-Node* GraphKit::set_results_for_java_call(CallJavaNode* call, bool separate_io_proj) {
+Node* GraphKit::set_results_for_java_call(CallJavaNode* call, bool separate_io_proj, bool deoptimize) {
if (stopped()) return top(); // maybe the call folded up?
// Capture the return value, if any.
@@ -1785,7 +1785,7 @@
// Note: Since any out-of-line call can produce an exception,
// we always insert an I_O projection from the call into the result.
- make_slow_call_ex(call, env()->Throwable_klass(), separate_io_proj);
+ make_slow_call_ex(call, env()->Throwable_klass(), separate_io_proj, deoptimize);
if (separate_io_proj) {
// The caller requested separate projections be used by the fall
@@ -2571,7 +2571,7 @@
Deoptimization::Action_none);
} else {
// Create an exception state also.
- // Use an exact type if the caller has specified a specific exception.
+ // Use an exact type if the caller has a specific exception.
const Type* ex_type = TypeOopPtr::make_from_klass_unique(ex_klass)->cast_to_ptr_type(TypePtr::NotNull);
Node* ex_oop = new CreateExNode(ex_type, control(), i_o);
add_exception_state(make_exception_state(_gvn.transform(ex_oop)));
--- a/src/hotspot/share/opto/graphKit.hpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/opto/graphKit.hpp Mon Aug 27 16:02:55 2018 -0400
@@ -693,7 +693,7 @@
// Finish up a java call that was started by set_edges_for_java_call.
// Call add_exception on any throw arising from the call.
// Return the call result (transformed).
- Node* set_results_for_java_call(CallJavaNode* call, bool separate_io_proj = false);
+ Node* set_results_for_java_call(CallJavaNode* call, bool separate_io_proj = false, bool deoptimize = false);
// Similar to set_edges_for_java_call, but simplified for runtime calls.
void set_predefined_output_for_runtime_call(Node* call) {
--- a/src/hotspot/share/opto/library_call.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/opto/library_call.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -4386,7 +4386,8 @@
if (!stopped()) {
PreserveJVMState pjvms(this);
CallJavaNode* slow_call = generate_method_call(vmIntrinsics::_clone, is_virtual);
- Node* slow_result = set_results_for_java_call(slow_call);
+ // We need to deoptimize on exception (see comment above)
+ Node* slow_result = set_results_for_java_call(slow_call, false, /* deoptimize */ true);
// this->control() comes from set_results_for_java_call
result_reg->init_req(_slow_path, control());
result_val->init_req(_slow_path, slow_result);
--- a/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "classfile/dictionary.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/systemDictionary.hpp"
#include "gc/shared/collectedHeap.hpp"
@@ -39,16 +40,7 @@
Stack<jclass, mtInternal> _classStack;
JvmtiEnv* _env;
Thread* _cur_thread;
-
-public:
- LoadedClassesClosure(Thread* thread, JvmtiEnv* env) : _env(env), _cur_thread(thread) {
- assert(_cur_thread == Thread::current(), "must be current thread");
- }
-
- void do_klass(Klass* k) {
- // Collect all jclasses
- _classStack.push((jclass) _env->jni_reference(Handle(_cur_thread, k->java_mirror())));
- }
+ bool _dictionary_walk;
int extract(jclass* result_list) {
// The size of the Stack will be 0 after extract, so get it here
@@ -68,198 +60,46 @@
int get_count() {
return (int)_classStack.size();
}
-};
-// The closure for GetClassLoaderClasses
-class JvmtiGetLoadedClassesClosure : public StackObj {
- // Since the ClassLoaderDataGraph::dictionary_all_entries_do callback
- // doesn't pass a closureData pointer,
- // we use a thread-local slot to hold a pointer to
- // a stack allocated instance of this structure.
- private:
- jobject _initiatingLoader;
- int _count;
- Handle* _list;
- int _index;
-
- private:
- // Getting and setting the thread local pointer
- static JvmtiGetLoadedClassesClosure* get_this() {
- JvmtiGetLoadedClassesClosure* result = NULL;
- JavaThread* thread = JavaThread::current();
- result = thread->get_jvmti_get_loaded_classes_closure();
- return result;
- }
- static void set_this(JvmtiGetLoadedClassesClosure* that) {
- JavaThread* thread = JavaThread::current();
- thread->set_jvmti_get_loaded_classes_closure(that);
- }
-
- public:
- // Constructor/Destructor
- JvmtiGetLoadedClassesClosure() {
- JvmtiGetLoadedClassesClosure* that = get_this();
- assert(that == NULL, "JvmtiGetLoadedClassesClosure in use");
- _initiatingLoader = NULL;
- _count = 0;
- _list = NULL;
- _index = 0;
- set_this(this);
- }
-
- JvmtiGetLoadedClassesClosure(jobject initiatingLoader) {
- JvmtiGetLoadedClassesClosure* that = get_this();
- assert(that == NULL, "JvmtiGetLoadedClassesClosure in use");
- _initiatingLoader = initiatingLoader;
- _count = 0;
- _list = NULL;
- _index = 0;
- set_this(this);
- }
-
- ~JvmtiGetLoadedClassesClosure() {
- JvmtiGetLoadedClassesClosure* that = get_this();
- assert(that != NULL, "JvmtiGetLoadedClassesClosure not found");
- set_this(NULL);
- _initiatingLoader = NULL;
- _count = 0;
- if (_list != NULL) {
- FreeHeap(_list);
- _list = NULL;
- }
- _index = 0;
- }
-
- // Accessors.
- jobject get_initiatingLoader() {
- return _initiatingLoader;
- }
-
- int get_count() {
- return _count;
+public:
+ LoadedClassesClosure(JvmtiEnv* env, bool dictionary_walk) :
+ _env(env),
+ _cur_thread(Thread::current()),
+ _dictionary_walk(dictionary_walk) {
}
- void set_count(int value) {
- _count = value;
- }
-
- Handle* get_list() {
- return _list;
- }
-
- void set_list(Handle* value) {
- _list = value;
- }
-
- int get_index() {
- return _index;
- }
-
- void set_index(int value) {
- _index = value;
- }
-
- Handle get_element(int index) {
- if ((_list != NULL) && (index < _count)) {
- return _list[index];
- } else {
- assert(false, "empty get_element");
- return Handle();
- }
- }
-
- void set_element(int index, Handle value) {
- if ((_list != NULL) && (index < _count)) {
- _list[index] = value;
- } else {
- assert(false, "bad set_element");
- }
- }
-
- // Other predicates
- bool available() {
- return (_list != NULL);
- }
-
-#ifdef ASSERT
- // For debugging.
- void check(int limit) {
- for (int i = 0; i < limit; i += 1) {
- assert(Universe::heap()->is_in(get_element(i)()), "check fails");
- }
- }
-#endif
-
- // Public methods that get called within the scope of the closure
- void allocate() {
- _list = NEW_C_HEAP_ARRAY(Handle, _count, mtInternal);
- assert(_list != NULL, "Out of memory");
- if (_list == NULL) {
- _count = 0;
- }
- }
-
- void extract(JvmtiEnv *env, jclass* result) {
- for (int index = 0; index < _count; index += 1) {
- result[index] = (jclass) env->jni_reference(get_element(index));
- }
- }
-
- static void increment_with_loader(InstanceKlass* k, ClassLoaderData* loader_data) {
- JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
- oop class_loader = loader_data->class_loader();
- if (class_loader == JNIHandles::resolve(that->get_initiatingLoader())) {
- for (Klass* l = k; l != NULL; l = l->array_klass_or_null()) {
- that->set_count(that->get_count() + 1);
+ void do_klass(Klass* k) {
+ // Collect all jclasses
+ _classStack.push((jclass) _env->jni_reference(Handle(_cur_thread, k->java_mirror())));
+ if (_dictionary_walk) {
+ // Collect array classes this way when walking the dictionary (because array classes are
+ // not in the dictionary).
+ for (Klass* l = k->array_klass_or_null(); l != NULL; l = l->array_klass_or_null()) {
+ _classStack.push((jclass) _env->jni_reference(Handle(_cur_thread, l->java_mirror())));
}
}
}
- static void add_with_loader(InstanceKlass* k, ClassLoaderData* loader_data) {
- JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
- if (that->available()) {
- oop class_loader = loader_data->class_loader();
- if (class_loader == JNIHandles::resolve(that->get_initiatingLoader())) {
- Thread *thread = Thread::current();
- for (Klass* l = k; l != NULL; l = l->array_klass_or_null()) {
- Handle mirror(thread, l->java_mirror());
- that->set_element(that->get_index(), mirror);
- that->set_index(that->get_index() + 1);
- }
- }
- }
- }
+ jvmtiError get_result(JvmtiEnv *env, jint* classCountPtr, jclass** classesPtr) {
+ // Return results by extracting the collected contents into a list
+ // allocated via JvmtiEnv
+ jclass* result_list;
+ jvmtiError error = env->Allocate(get_count() * sizeof(jclass),
+ (unsigned char**)&result_list);
- // increment the count for the given basic type array class (and any
- // multi-dimensional arrays). For example, for [B we check for
- // [[B, [[[B, .. and the count is incremented for each one that exists.
- static void increment_for_basic_type_arrays(Klass* k) {
- JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
- assert(that != NULL, "no JvmtiGetLoadedClassesClosure");
- for (Klass* l = k; l != NULL; l = l->array_klass_or_null()) {
- that->set_count(that->get_count() + 1);
+ if (error == JVMTI_ERROR_NONE) {
+ int count = extract(result_list);
+ *classCountPtr = count;
+ *classesPtr = result_list;
}
- }
-
- // add the basic type array class and its multi-dimensional array classes to the list
- static void add_for_basic_type_arrays(Klass* k) {
- JvmtiGetLoadedClassesClosure* that = JvmtiGetLoadedClassesClosure::get_this();
- assert(that != NULL, "no JvmtiGetLoadedClassesClosure");
- assert(that->available(), "no list");
- Thread *thread = Thread::current();
- for (Klass* l = k; l != NULL; l = l->array_klass_or_null()) {
- Handle mirror(thread, l->java_mirror());
- that->set_element(that->get_index(), mirror);
- that->set_index(that->get_index() + 1);
- }
+ return error;
}
};
-
jvmtiError
JvmtiGetLoadedClasses::getLoadedClasses(JvmtiEnv *env, jint* classCountPtr, jclass** classesPtr) {
- LoadedClassesClosure closure(Thread::current(), env);
+ LoadedClassesClosure closure(env, false);
{
// To get a consistent list of classes we need MultiArray_lock to ensure
// array classes aren't created.
@@ -270,56 +110,35 @@
ClassLoaderDataGraph::loaded_classes_do(&closure);
}
- // Return results by extracting the collected contents into a list
- // allocated via JvmtiEnv
- jclass* result_list;
- jvmtiError error = env->Allocate(closure.get_count() * sizeof(jclass),
- (unsigned char**)&result_list);
-
- if (error == JVMTI_ERROR_NONE) {
- int count = closure.extract(result_list);
- *classCountPtr = count;
- *classesPtr = result_list;
- }
- return error;
+ return closure.get_result(env, classCountPtr, classesPtr);
}
jvmtiError
JvmtiGetLoadedClasses::getClassLoaderClasses(JvmtiEnv *env, jobject initiatingLoader,
jint* classCountPtr, jclass** classesPtr) {
- // Since ClassLoaderDataGraph::dictionary_all_entries_do only takes a function pointer
- // and doesn't call back with a closure data pointer,
- // we can only pass static methods.
- JvmtiGetLoadedClassesClosure closure(initiatingLoader);
+
+ LoadedClassesClosure closure(env, true);
{
// To get a consistent list of classes we need MultiArray_lock to ensure
- // array classes aren't created, and SystemDictionary_lock to ensure that
- // classes aren't added to the class loader data dictionaries.
+ // array classes aren't created during this walk.
MutexLocker ma(MultiArray_lock);
MutexLocker sd(SystemDictionary_lock);
- // First, count the classes in the class loader data dictionaries which have this loader recorded
- // as an initiating loader. For basic type arrays this information is not recorded
- // so GetClassLoaderClasses will return all of the basic type arrays. This is okay
- // because the defining loader for basic type arrays is always the boot class loader
- // and these classes are "visible" to all loaders.
- ClassLoaderDataGraph::dictionary_all_entries_do(&JvmtiGetLoadedClassesClosure::increment_with_loader);
- Universe::basic_type_classes_do(&JvmtiGetLoadedClassesClosure::increment_for_basic_type_arrays);
- // Next, fill in the classes
- closure.allocate();
- ClassLoaderDataGraph::dictionary_all_entries_do(&JvmtiGetLoadedClassesClosure::add_with_loader);
- Universe::basic_type_classes_do(&JvmtiGetLoadedClassesClosure::add_for_basic_type_arrays);
- // Drop the SystemDictionary_lock, so the results could be wrong from here,
- // but we still have a snapshot.
+ oop loader = JNIHandles::resolve(initiatingLoader);
+ // All classes loaded from this loader as initiating loader are
+ // requested, so only need to walk this loader's ClassLoaderData
+ // dictionary, or the NULL ClassLoaderData dictionary for bootstrap loader.
+ if (loader != NULL) {
+ ClassLoaderData* data = java_lang_ClassLoader::loader_data(loader);
+ // ClassLoader may not be used yet for loading.
+ if (data != NULL && data->dictionary() != NULL) {
+ data->dictionary()->all_entries_do(&closure);
+ }
+ } else {
+ ClassLoaderData::the_null_class_loader_data()->dictionary()->all_entries_do(&closure);
+ }
+ // Get basic arrays for all loaders.
+ Universe::basic_type_classes_do(&closure);
}
- // Post results
- jclass* result_list;
- jvmtiError err = env->Allocate(closure.get_count() * sizeof(jclass),
- (unsigned char**)&result_list);
- if (err != JVMTI_ERROR_NONE) {
- return err;
- }
- closure.extract(env, result_list);
- *classCountPtr = closure.get_count();
- *classesPtr = result_list;
- return JVMTI_ERROR_NONE;
+
+ return closure.get_result(env, classCountPtr, classesPtr);
}
--- a/src/hotspot/share/runtime/deoptimization.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/runtime/deoptimization.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -703,13 +703,12 @@
// a given bytecode or the state after, so we try both
if (!Bytecodes::is_invoke(cur_code) && cur_code != Bytecodes::_athrow) {
// Get expression stack size for the next bytecode
+ InterpreterOopMap next_mask;
+ OopMapCache::compute_one_oop_map(mh, str.bci(), &next_mask);
+ next_mask_expression_stack_size = next_mask.expression_stack_size();
if (Bytecodes::is_invoke(next_code)) {
Bytecode_invoke invoke(mh, str.bci());
- next_mask_expression_stack_size = invoke.size_of_parameters();
- } else {
- InterpreterOopMap next_mask;
- OopMapCache::compute_one_oop_map(mh, str.bci(), &next_mask);
- next_mask_expression_stack_size = next_mask.expression_stack_size();
+ next_mask_expression_stack_size += invoke.size_of_parameters();
}
// Need to subtract off the size of the result type of
// the bytecode because this is not described in the
@@ -739,28 +738,30 @@
(is_top_frame && (exec_mode == Unpack_uncommon_trap || exec_mode == Unpack_reexecute || el->should_reexecute()) &&
(iframe->interpreter_frame_expression_stack_size() == mask.expression_stack_size() + cur_invoke_parameter_size))
)) {
- ttyLocker ttyl;
+ {
+ ttyLocker ttyl;
- // Print out some information that will help us debug the problem
- tty->print_cr("Wrong number of expression stack elements during deoptimization");
- tty->print_cr(" Error occurred while verifying frame %d (0..%d, 0 is topmost)", i, cur_array->frames() - 1);
- tty->print_cr(" Fabricated interpreter frame had %d expression stack elements",
- iframe->interpreter_frame_expression_stack_size());
- tty->print_cr(" Interpreter oop map had %d expression stack elements", mask.expression_stack_size());
- tty->print_cr(" try_next_mask = %d", try_next_mask);
- tty->print_cr(" next_mask_expression_stack_size = %d", next_mask_expression_stack_size);
- tty->print_cr(" callee_size_of_parameters = %d", callee_size_of_parameters);
- tty->print_cr(" callee_max_locals = %d", callee_max_locals);
- tty->print_cr(" top_frame_expression_stack_adjustment = %d", top_frame_expression_stack_adjustment);
- tty->print_cr(" exec_mode = %d", exec_mode);
- tty->print_cr(" cur_invoke_parameter_size = %d", cur_invoke_parameter_size);
- tty->print_cr(" Thread = " INTPTR_FORMAT ", thread ID = %d", p2i(thread), thread->osthread()->thread_id());
- tty->print_cr(" Interpreted frames:");
- for (int k = 0; k < cur_array->frames(); k++) {
- vframeArrayElement* el = cur_array->element(k);
- tty->print_cr(" %s (bci %d)", el->method()->name_and_sig_as_C_string(), el->bci());
- }
- cur_array->print_on_2(tty);
+ // Print out some information that will help us debug the problem
+ tty->print_cr("Wrong number of expression stack elements during deoptimization");
+ tty->print_cr(" Error occurred while verifying frame %d (0..%d, 0 is topmost)", i, cur_array->frames() - 1);
+ tty->print_cr(" Fabricated interpreter frame had %d expression stack elements",
+ iframe->interpreter_frame_expression_stack_size());
+ tty->print_cr(" Interpreter oop map had %d expression stack elements", mask.expression_stack_size());
+ tty->print_cr(" try_next_mask = %d", try_next_mask);
+ tty->print_cr(" next_mask_expression_stack_size = %d", next_mask_expression_stack_size);
+ tty->print_cr(" callee_size_of_parameters = %d", callee_size_of_parameters);
+ tty->print_cr(" callee_max_locals = %d", callee_max_locals);
+ tty->print_cr(" top_frame_expression_stack_adjustment = %d", top_frame_expression_stack_adjustment);
+ tty->print_cr(" exec_mode = %d", exec_mode);
+ tty->print_cr(" cur_invoke_parameter_size = %d", cur_invoke_parameter_size);
+ tty->print_cr(" Thread = " INTPTR_FORMAT ", thread ID = %d", p2i(thread), thread->osthread()->thread_id());
+ tty->print_cr(" Interpreted frames:");
+ for (int k = 0; k < cur_array->frames(); k++) {
+ vframeArrayElement* el = cur_array->element(k);
+ tty->print_cr(" %s (bci %d)", el->method()->name_and_sig_as_C_string(), el->bci());
+ }
+ cur_array->print_on_2(tty);
+ } // release tty lock before calling guarantee
guarantee(false, "wrong number of expression stack elements during deopt");
}
VerifyOopClosure verify;
--- a/src/hotspot/share/runtime/frame.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/runtime/frame.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -721,6 +721,14 @@
st->print("v ~ExceptionBlob");
} else if (_cb->is_safepoint_stub()) {
st->print("v ~SafepointBlob");
+ } else if (_cb->is_adapter_blob()) {
+ st->print("v ~AdapterBlob");
+ } else if (_cb->is_vtable_blob()) {
+ st->print("v ~VtableBlob");
+ } else if (_cb->is_method_handles_adapter_blob()) {
+ st->print("v ~MethodHandlesAdapterBlob");
+ } else if (_cb->is_uncommon_trap_stub()) {
+ st->print("v ~UncommonTrapBlob");
} else {
st->print("v blob " PTR_FORMAT, p2i(pc()));
}
--- a/src/hotspot/share/runtime/mutexLocker.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/runtime/mutexLocker.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -63,7 +63,7 @@
Mutex* AdapterHandlerLibrary_lock = NULL;
Mutex* SignatureHandlerLibrary_lock = NULL;
Mutex* VtableStubs_lock = NULL;
-Mutex* SymbolTable_lock = NULL;
+Mutex* SymbolArena_lock = NULL;
Mutex* StringTable_lock = NULL;
Monitor* StringDedupQueue_lock = NULL;
Mutex* StringDedupTable_lock = NULL;
@@ -76,6 +76,7 @@
Monitor* Safepoint_lock = NULL;
Monitor* SerializePage_lock = NULL;
Monitor* Threads_lock = NULL;
+Mutex* NamedThreadsList_lock = NULL;
Monitor* CGC_lock = NULL;
Monitor* STS_lock = NULL;
Monitor* FullGCCount_lock = NULL;
@@ -234,9 +235,9 @@
def(InlineCacheBuffer_lock , PaddedMutex , leaf, true, Monitor::_safepoint_check_always);
def(VMStatistic_lock , PaddedMutex , leaf, false, Monitor::_safepoint_check_always);
def(ExpandHeap_lock , PaddedMutex , leaf, true, Monitor::_safepoint_check_always); // Used during compilation by VM thread
- def(JNIHandleBlockFreeList_lock , PaddedMutex , leaf, true, Monitor::_safepoint_check_never); // handles are used by VM thread
+ def(JNIHandleBlockFreeList_lock , PaddedMutex , leaf-1, true, Monitor::_safepoint_check_never); // handles are used by VM thread
def(SignatureHandlerLibrary_lock , PaddedMutex , leaf, false, Monitor::_safepoint_check_always);
- def(SymbolTable_lock , PaddedMutex , leaf+2, true, Monitor::_safepoint_check_always);
+ def(SymbolArena_lock , PaddedMutex , leaf+2, true, Monitor::_safepoint_check_never);
def(StringTable_lock , PaddedMutex , leaf, true, Monitor::_safepoint_check_always);
def(ProfilePrint_lock , PaddedMutex , leaf, false, Monitor::_safepoint_check_always); // serial profile printing
def(ExceptionCache_lock , PaddedMutex , leaf, false, Monitor::_safepoint_check_always); // serial profile printing
@@ -256,6 +257,7 @@
def(Safepoint_lock , PaddedMonitor, safepoint, true, Monitor::_safepoint_check_sometimes); // locks SnippetCache_lock/Threads_lock
def(Threads_lock , PaddedMonitor, barrier, true, Monitor::_safepoint_check_sometimes);
+ def(NamedThreadsList_lock , PaddedMutex, leaf, true, Monitor::_safepoint_check_never);
def(VMOperationQueue_lock , PaddedMonitor, nonleaf, true, Monitor::_safepoint_check_sometimes); // VM_thread allowed to block on these
def(VMOperationRequest_lock , PaddedMonitor, nonleaf, true, Monitor::_safepoint_check_sometimes);
@@ -278,7 +280,7 @@
def(CompileTaskAlloc_lock , PaddedMutex , nonleaf+2, true, Monitor::_safepoint_check_always);
def(CompileStatistics_lock , PaddedMutex , nonleaf+2, false, Monitor::_safepoint_check_always);
def(DirectivesStack_lock , PaddedMutex , special, true, Monitor::_safepoint_check_never);
- def(MultiArray_lock , PaddedMutex , nonleaf+2, false, Monitor::_safepoint_check_always); // locks SymbolTable_lock
+ def(MultiArray_lock , PaddedMutex , nonleaf+2, false, Monitor::_safepoint_check_always);
def(JvmtiThreadState_lock , PaddedMutex , nonleaf+2, false, Monitor::_safepoint_check_always); // Used by JvmtiThreadState/JvmtiEventController
def(Management_lock , PaddedMutex , nonleaf+2, false, Monitor::_safepoint_check_always); // used for JVM management
--- a/src/hotspot/share/runtime/mutexLocker.hpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/runtime/mutexLocker.hpp Mon Aug 27 16:02:55 2018 -0400
@@ -57,7 +57,7 @@
extern Mutex* AdapterHandlerLibrary_lock; // a lock on the AdapterHandlerLibrary
extern Mutex* SignatureHandlerLibrary_lock; // a lock on the SignatureHandlerLibrary
extern Mutex* VtableStubs_lock; // a lock on the VtableStubs
-extern Mutex* SymbolTable_lock; // a lock on the symbol table
+extern Mutex* SymbolArena_lock; // a lock on the symbol table arena
extern Mutex* StringTable_lock; // a lock on the interned string table
extern Monitor* StringDedupQueue_lock; // a lock on the string deduplication queue
extern Mutex* StringDedupTable_lock; // a lock on the string deduplication table
@@ -72,6 +72,7 @@
extern Monitor* Safepoint_lock; // a lock used by the safepoint abstraction
extern Monitor* Threads_lock; // a lock on the Threads table of active Java threads
// (also used by Safepoints too to block threads creation/destruction)
+extern Mutex* NamedThreadsList_lock; // a lock on the NamedThreads list
extern Monitor* CGC_lock; // used for coordination between
// fore- & background GC threads.
extern Monitor* STS_lock; // used for joining/leaving SuspendibleThreadSet.
--- a/src/hotspot/share/runtime/thread.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/runtime/thread.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -114,6 +114,7 @@
#include "utilities/events.hpp"
#include "utilities/macros.hpp"
#include "utilities/preserveException.hpp"
+#include "utilities/singleWriterSynchronizer.hpp"
#include "utilities/vmError.hpp"
#if INCLUDE_JVMCI
#include "jvmci/jvmciCompiler.hpp"
@@ -1206,15 +1207,61 @@
THREAD);
}
+// List of all NamedThreads and safe iteration over that list.
+
+class NamedThread::List {
+public:
+ NamedThread* volatile _head;
+ SingleWriterSynchronizer _protect;
+
+ List() : _head(NULL), _protect() {}
+};
+
+NamedThread::List NamedThread::_the_list;
+
+NamedThread::Iterator::Iterator() :
+ _protect_enter(_the_list._protect.enter()),
+ _current(OrderAccess::load_acquire(&_the_list._head))
+{}
+
+NamedThread::Iterator::~Iterator() {
+ _the_list._protect.exit(_protect_enter);
+}
+
+void NamedThread::Iterator::step() {
+ assert(!end(), "precondition");
+ _current = OrderAccess::load_acquire(&_current->_next_named_thread);
+}
+
// NamedThread -- non-JavaThread subclasses with multiple
// uniquely named instances should derive from this.
-NamedThread::NamedThread() : Thread() {
- _name = NULL;
- _processed_thread = NULL;
- _gc_id = GCId::undefined();
+NamedThread::NamedThread() :
+ Thread(),
+ _name(NULL),
+ _processed_thread(NULL),
+ _gc_id(GCId::undefined()),
+ _next_named_thread(NULL)
+{
+ // Add this thread to _the_list.
+ MutexLockerEx lock(NamedThreadsList_lock, Mutex::_no_safepoint_check_flag);
+ _next_named_thread = _the_list._head;
+ OrderAccess::release_store(&_the_list._head, this);
}
NamedThread::~NamedThread() {
+ // Remove this thread from _the_list.
+ {
+ MutexLockerEx lock(NamedThreadsList_lock, Mutex::_no_safepoint_check_flag);
+ NamedThread* volatile* p = &_the_list._head;
+ for (NamedThread* t = *p; t != NULL; p = &t->_next_named_thread, t = *p) {
+ if (t == this) {
+ *p = this->_next_named_thread;
+ // Wait for any in-progress iterators.
+ _the_list._protect.synchronize();
+ break;
+ }
+ }
+ }
if (_name != NULL) {
FREE_C_HEAP_ARRAY(char, _name);
_name = NULL;
@@ -1520,7 +1567,6 @@
_is_method_handle_return = 0;
_jvmti_thread_state= NULL;
_should_post_on_exceptions_flag = JNI_FALSE;
- _jvmti_get_loaded_classes_closure = NULL;
_interp_only_mode = 0;
_special_runtime_exit_condition = _no_async_condition;
_pending_async_exception = NULL;
--- a/src/hotspot/share/runtime/thread.hpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/runtime/thread.hpp Mon Aug 27 16:02:55 2018 -0400
@@ -63,7 +63,6 @@
class ThreadsSMRSupport;
class JvmtiThreadState;
-class JvmtiGetLoadedClassesClosure;
class ThreadStatistics;
class ConcurrentLocksDump;
class ParkEvent;
@@ -103,6 +102,7 @@
// - JavaThread
// - various subclasses eg CompilerThread, ServiceThread
// - WatcherThread
+// - JfrSamplerThread
class Thread: public ThreadShadow {
friend class VMStructs;
@@ -776,6 +776,10 @@
// log JavaThread being processed by oops_do
JavaThread* _processed_thread;
uint _gc_id; // The current GC id when a thread takes part in GC
+ NamedThread* volatile _next_named_thread;
+
+ class List;
+ static List _the_list;
public:
NamedThread();
@@ -791,6 +795,31 @@
void set_gc_id(uint gc_id) { _gc_id = gc_id; }
uint gc_id() { return _gc_id; }
+
+ class Iterator;
+};
+
+// Provides iteration over the list of NamedThreads. Because list
+// management occurs in the NamedThread constructor and destructor,
+// entries in the list may not be fully constructed instances of a
+// derived class. Threads created after an iterator is constructed
+// will not be visited by the iterator. The scope of an iterator is a
+// critical section; there must be no safepoint checks in that scope.
+class NamedThread::Iterator : public StackObj {
+ uint _protect_enter;
+ NamedThread* _current;
+
+ // Noncopyable.
+ Iterator(const Iterator&);
+ Iterator& operator=(const Iterator&);
+
+public:
+ Iterator();
+ ~Iterator();
+
+ bool end() const { return _current == NULL; }
+ NamedThread* current() const { return _current; }
+ void step();
};
// Worker threads are named and have an id of an assigned work.
@@ -1855,8 +1884,6 @@
// the specified JavaThread is exiting.
JvmtiThreadState *jvmti_thread_state() const { return _jvmti_thread_state; }
static ByteSize jvmti_thread_state_offset() { return byte_offset_of(JavaThread, _jvmti_thread_state); }
- void set_jvmti_get_loaded_classes_closure(JvmtiGetLoadedClassesClosure* value) { _jvmti_get_loaded_classes_closure = value; }
- JvmtiGetLoadedClassesClosure* get_jvmti_get_loaded_classes_closure() const { return _jvmti_get_loaded_classes_closure; }
// JVMTI PopFrame support
// Setting and clearing popframe_condition
@@ -1908,7 +1935,6 @@
private:
JvmtiThreadState *_jvmti_thread_state;
- JvmtiGetLoadedClassesClosure* _jvmti_get_loaded_classes_closure;
// Used by the interpreter in fullspeed mode for frame pop, method
// entry, method exit and single stepping support. This field is
--- a/src/hotspot/share/utilities/globalCounter.cpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/utilities/globalCounter.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -71,5 +71,7 @@
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
ctc.do_thread(thread);
}
- ctc.do_thread(VMThread::vm_thread());
+ for (NamedThread::Iterator nti; !nti.end(); nti.step()) {
+ ctc.do_thread(nti.current());
+ }
}
--- a/src/hotspot/share/utilities/globalCounter.inline.hpp Mon Aug 27 16:01:38 2018 -0400
+++ b/src/hotspot/share/utilities/globalCounter.inline.hpp Mon Aug 27 16:02:55 2018 -0400
@@ -31,16 +31,16 @@
inline void GlobalCounter::critical_section_begin(Thread *thread) {
assert(thread == Thread::current(), "must be current thread");
- assert(thread->is_VM_thread() || thread->is_Java_thread(), "must be VMThread or JavaThread");
- assert((*thread->get_rcu_counter() & COUNTER_ACTIVE) == 0x0, "nestled critical sections, not supported yet");
+ assert(thread->is_Named_thread() || thread->is_Java_thread(), "must be NamedThread or JavaThread");
+ assert((*thread->get_rcu_counter() & COUNTER_ACTIVE) == 0x0, "nested critical sections, not supported yet");
uintx gbl_cnt = OrderAccess::load_acquire(&_global_counter._counter);
OrderAccess::release_store_fence(thread->get_rcu_counter(), gbl_cnt | COUNTER_ACTIVE);
}
inline void GlobalCounter::critical_section_end(Thread *thread) {
assert(thread == Thread::current(), "must be current thread");
- assert(thread->is_VM_thread() || thread->is_Java_thread(), "must be VMThread or JavaThread");
- assert((*thread->get_rcu_counter() & COUNTER_ACTIVE) == COUNTER_ACTIVE, "must be in ctitical section");
+ assert(thread->is_Named_thread() || thread->is_Java_thread(), "must be NamedThread or JavaThread");
+ assert((*thread->get_rcu_counter() & COUNTER_ACTIVE) == COUNTER_ACTIVE, "must be in critical section");
// Mainly for debugging we set it to 'now'.
uintx gbl_cnt = OrderAccess::load_acquire(&_global_counter._counter);
OrderAccess::release_store(thread->get_rcu_counter(), gbl_cnt);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/utilities/singleWriterSynchronizer.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/atomic.hpp"
+#include "runtime/orderAccess.hpp"
+#include "runtime/os.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/singleWriterSynchronizer.hpp"
+#include "utilities/macros.hpp"
+
+SingleWriterSynchronizer::SingleWriterSynchronizer() :
+ _enter(0),
+ _exit(),
+ // The initial value of 1 for _waiting_for puts it on the inactive
+ // track, so no thread exiting a critical section will match it.
+ _waiting_for(1),
+ _wakeup()
+ DEBUG_ONLY(COMMA _writers(0))
+{}
+
+// Wait until all threads that entered a critical section before
+// synchronization have exited that critical section.
+void SingleWriterSynchronizer::synchronize() {
+ // Side-effect in assert balanced by debug-only dec at end.
+ assert(Atomic::add(1u, &_writers) == 1u, "multiple writers");
+ // We don't know anything about the muxing between this invocation
+ // and invocations in other threads. We must start with the latest
+ // _enter polarity, else we could clobber the wrong _exit value on
+ // the first iteration. So fence to ensure everything here follows
+ // whatever muxing was used.
+ OrderAccess::fence();
+ uint value = _enter;
+ // (1) Determine the old and new exit counters, based on the
+ // polarity (bit0 value) of the on-entry enter counter.
+ volatile uint* new_ptr = &_exit[(value + 1) & 1];
+ // (2) Change the in-use exit counter to the new counter, by adding
+ // 1 to the enter counter (flipping the polarity), meanwhile
+ // "simultaneously" initializing the new exit counter to that enter
+ // value. Note: The new exit counter is not being used by read
+ // operations until this change of _enter succeeds.
+ uint old;
+ do {
+ old = value;
+ *new_ptr = ++value;
+ value = Atomic::cmpxchg(value, &_enter, old);
+ } while (old != value);
+ // Critical sections entered before we changed the polarity will use
+ // the old exit counter. Critical sections entered after the change
+ // will use the new exit counter.
+ volatile uint* old_ptr = &_exit[old & 1];
+ assert(old_ptr != new_ptr, "invariant");
+ // (3) Inform threads in in-progress critical sections that there is
+ // a pending synchronize waiting. The thread that completes the
+ // request (_exit value == old) will signal the _wakeup semaphore to
+ // allow us to proceed.
+ _waiting_for = old;
+ // Write of _waiting_for must precede read of _exit and associated
+ // conditional semaphore wait. If they were re-ordered then a
+ // critical section exit could miss the wakeup request, failing to
+ // signal us while we're waiting.
+ OrderAccess::fence();
+ // (4) Wait for all the critical sections started before the change
+ // to complete, e.g. for the value of old_ptr to catch up with old.
+ // Loop because there could be pending wakeups unrelated to this
+ // synchronize request.
+ while (old != OrderAccess::load_acquire(old_ptr)) {
+ _wakeup.wait();
+ }
+ // (5) Drain any pending wakeups. A critical section exit may have
+ // completed our request and seen our _waiting_for before we checked
+ // for completion. There are also possible (though rare) spurious
+ // wakeup signals in the timing gap between changing the _enter
+ // polarity and setting _waiting_for. Enough of any of those could
+ // lead to semaphore overflow. This doesn't guarantee no unrelated
+ // wakeups for the next wait, but prevents unbounded accumulation.
+ while (_wakeup.trywait()) {}
+ DEBUG_ONLY(Atomic::dec(&_writers);)
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/utilities/singleWriterSynchronizer.hpp Mon Aug 27 16:02:55 2018 -0400
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_UTILITIES_SINGLEWRITERSYNCHRONIZER_HPP
+#define SHARE_UTILITIES_SINGLEWRITERSYNCHRONIZER_HPP
+
+#include "memory/allocation.hpp"
+#include "runtime/atomic.hpp"
+#include "runtime/semaphore.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
+
+// Synchronization primitive inspired by RCU.
+//
+// Any number of threads may enter critical sections associated with a
+// synchronizer object. One (at a time) other thread may wait for the
+// completion of all critical sections for the synchronizer object
+// that were extent when the wait was initiated. Usage is that there
+// is some state that can be accessed either before or after some
+// change. An accessing thread performs the access within a critical
+// section. A writer thread performs the state change, and then waits
+// for critical sections to complete, thereby ensuring there are no
+// threads in a critical section that might have seen the old state.
+//
+// Generally, GlobalCounter should be used instead of this class, as
+// GlobalCounter has measurably better performance and doesn't have
+// the single writer at a time restriction. Use this only in
+// situations where GlobalCounter won't work for some reason, such as
+// nesting. But note that nesting often indicates other problems, and
+// may risk deadlock.
+class SingleWriterSynchronizer {
+ volatile uint _enter;
+ volatile uint _exit[2];
+ volatile uint _waiting_for;
+ Semaphore _wakeup;
+
+ DEBUG_ONLY(volatile uint _writers;)
+
+ // Noncopyable.
+ SingleWriterSynchronizer(const SingleWriterSynchronizer&);
+ SingleWriterSynchronizer& operator=(const SingleWriterSynchronizer&);
+
+public:
+ SingleWriterSynchronizer();
+
+ // Enter a critical section for this synchronizer. Entering a
+ // critical section never blocks. While in a critical section, a
+ // thread should avoid blocking, or even take a long time. In
+ // particular, a thread must never safepoint while in a critical
+ // section.
+ // Precondition: The current thread must not already be in a
+ // critical section for this synchronizer.
+ inline uint enter();
+
+ // Exit a critical section for this synchronizer.
+ // Precondition: enter_value must be the result of the corresponding
+ // enter() for the critical section.
+ inline void exit(uint enter_value);
+
+ // Wait until all threads currently in a critical section for this
+ // synchronizer have exited their critical section. Threads that
+ // enter a critical section after the synchronization has started
+ // are not considered in the wait.
+ // Precondition: No other thread may be synchronizing on this
+ // synchronizer.
+ void synchronize();
+
+ // RAII class for managing enter/exit pairs.
+ class CriticalSection;
+};
+
+inline uint SingleWriterSynchronizer::enter() {
+ return Atomic::add(2u, &_enter);
+}
+
+inline void SingleWriterSynchronizer::exit(uint enter_value) {
+ uint exit_value = Atomic::add(2u, &_exit[enter_value & 1]);
+ // If this exit completes a synchronize request, wakeup possibly
+ // waiting synchronizer. Read of _waiting_for must follow the _exit
+ // update.
+ if (exit_value == _waiting_for) {
+ _wakeup.signal();
+ }
+}
+
+class SingleWriterSynchronizer::CriticalSection : public StackObj {
+ SingleWriterSynchronizer* _synchronizer;
+ uint _enter_value;
+
+public:
+ // Enter synchronizer's critical section.
+ explicit CriticalSection(SingleWriterSynchronizer* synchronizer) :
+ _synchronizer(synchronizer),
+ _enter_value(synchronizer->enter())
+ {}
+
+ // Exit synchronizer's critical section.
+ ~CriticalSection() {
+ _synchronizer->exit(_enter_value);
+ }
+};
+
+#endif // SHARE_UTILITIES_SINGLEWRITERSYNCHRONIZER_HPP
--- a/src/java.base/share/classes/java/io/FileSystem.java Mon Aug 27 16:01:38 2018 -0400
+++ b/src/java.base/share/classes/java/io/FileSystem.java Mon Aug 27 16:02:55 2018 -0400
@@ -231,18 +231,16 @@
// Flags for enabling/disabling performance optimizations for file
// name canonicalization
- static boolean useCanonCaches;
- static boolean useCanonPrefixCache;
+ static final boolean useCanonCaches;
+ static final boolean useCanonPrefixCache;
private static boolean getBooleanProperty(String prop, boolean defaultVal) {
- return Boolean.parseBoolean(System.getProperty(prop,
- String.valueOf(defaultVal)));
+ String value = System.getProperty(prop);
+ return (value != null) ? Boolean.parseBoolean(value) : defaultVal;
}
static {
- useCanonCaches = getBooleanProperty("sun.io.useCanonCaches",
- useCanonCaches);
- useCanonPrefixCache = getBooleanProperty("sun.io.useCanonPrefixCache",
- useCanonPrefixCache);
+ useCanonCaches = getBooleanProperty("sun.io.useCanonCaches", false);
+ useCanonPrefixCache = useCanonCaches && getBooleanProperty("sun.io.useCanonPrefixCache", false);
}
}
--- a/src/java.base/share/classes/java/lang/Integer.java Mon Aug 27 16:01:38 2018 -0400
+++ b/src/java.base/share/classes/java/lang/Integer.java Mon Aug 27 16:02:55 2018 -0400
@@ -1654,15 +1654,15 @@
*/
@HotSpotIntrinsicCandidate
public static int numberOfTrailingZeros(int i) {
- // HD, Figure 5-14
- int y;
- if (i == 0) return 32;
- int n = 31;
- y = i <<16; if (y != 0) { n = n -16; i = y; }
- y = i << 8; if (y != 0) { n = n - 8; i = y; }
- y = i << 4; if (y != 0) { n = n - 4; i = y; }
- y = i << 2; if (y != 0) { n = n - 2; i = y; }
- return n - ((i << 1) >>> 31);
+ // HD, Count trailing 0's
+ i = ~i & (i - 1);
+ if (i <= 0) return i & 32;
+ int n = 1;
+ if (i > 1 << 16) { n += 16; i >>>= 16; }
+ if (i > 1 << 8) { n += 8; i >>>= 8; }
+ if (i > 1 << 4) { n += 4; i >>>= 4; }
+ if (i > 1 << 2) { n += 2; i >>>= 2; }
+ return n + (i >>> 1);
}
/**
--- a/src/java.base/share/classes/java/lang/Long.java Mon Aug 27 16:01:38 2018 -0400
+++ b/src/java.base/share/classes/java/lang/Long.java Mon Aug 27 16:02:55 2018 -0400
@@ -1782,16 +1782,9 @@
*/
@HotSpotIntrinsicCandidate
public static int numberOfTrailingZeros(long i) {
- // HD, Figure 5-14
- int x, y;
- if (i == 0) return 64;
- int n = 63;
- y = (int)i; if (y != 0) { n = n -32; x = y; } else x = (int)(i>>>32);
- y = x <<16; if (y != 0) { n = n -16; x = y; }
- y = x << 8; if (y != 0) { n = n - 8; x = y; }
- y = x << 4; if (y != 0) { n = n - 4; x = y; }
- y = x << 2; if (y != 0) { n = n - 2; x = y; }
- return n - ((x << 1) >>> 31);
+ int x = (int)i;
+ return x == 0 ? 32 + Integer.numberOfTrailingZeros((int)(i >>> 32))
+ : Integer.numberOfTrailingZeros(x);
}
/**
--- a/src/java.base/share/classes/module-info.java Mon Aug 27 16:01:38 2018 -0400
+++ b/src/java.base/share/classes/module-info.java Mon Aug 27 16:02:55 2018 -0400
@@ -284,8 +284,6 @@
java.naming;
exports sun.security.rsa to
jdk.crypto.cryptoki;
- exports sun.security.ssl to
- java.security.jgss;
exports sun.security.timestamp to
jdk.jartool;
exports sun.security.tools to
--- a/src/java.base/share/classes/sun/security/provider/DSA.java Mon Aug 27 16:01:38 2018 -0400
+++ b/src/java.base/share/classes/sun/security/provider/DSA.java Mon Aug 27 16:02:55 2018 -0400
@@ -152,7 +152,7 @@
// check key size against hash output size for signing
// skip this check for verification to minimize impact on existing apps
- if (md.getAlgorithm() != "NullDigest20") {
+ if (!"NullDigest20".equals(md.getAlgorithm())) {
checkKey(params, md.getDigestLength()*8, md.getAlgorithm());
}
--- a/src/java.base/share/classes/sun/security/ssl/SSLExtensions.java Mon Aug 27 16:01:38 2018 -0400
+++ b/src/java.base/share/classes/sun/security/ssl/SSLExtensions.java Mon Aug 27 16:02:55 2018 -0400
@@ -43,7 +43,7 @@
// Extension map for debug logging
private final Map<Integer, byte[]> logMap =
- SSLLogger.isOn ? null : new LinkedHashMap<>();
+ SSLLogger.isOn ? new LinkedHashMap<>() : null;
SSLExtensions(HandshakeMessage handshakeMessage) {
this.handshakeMessage = handshakeMessage;
@@ -65,38 +65,59 @@
"): no sufficient data");
}
+ boolean isSupported = true;
SSLHandshake handshakeType = hm.handshakeType();
if (SSLExtension.isConsumable(extId) &&
SSLExtension.valueOf(handshakeType, extId) == null) {
- hm.handshakeContext.conContext.fatal(
+ if (extId == SSLExtension.CH_SUPPORTED_GROUPS.id &&
+ handshakeType == SSLHandshake.SERVER_HELLO) {
+ // Note: It does not comply to the specification. However,
+ // there are servers that send the supported_groups
+ // extension in ServerHello handshake message.
+ //
+ // TLS 1.3 should not send this extension. We may want to
+ // limit the workaround for TLS 1.2 and prior version only.
+ // However, the implementation of the limit is complicated
+ // and inefficient, and may not worthy the maintenance.
+ isSupported = false;
+ if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+ SSLLogger.warning(
+ "Received buggy supported_groups extension " +
+ "in the ServerHello handshake message");
+ }
+ } else {
+ hm.handshakeContext.conContext.fatal(
Alert.UNSUPPORTED_EXTENSION,
"extension (" + extId +
") should not be presented in " + handshakeType.name);
+ }
}
- boolean isSupported = false;
- for (SSLExtension extension : extensions) {
- if ((extension.id != extId) ||
- (extension.onLoadConsumer == null)) {
- continue;
- }
+ if (isSupported) {
+ isSupported = false;
+ for (SSLExtension extension : extensions) {
+ if ((extension.id != extId) ||
+ (extension.onLoadConsumer == null)) {
+ continue;
+ }
- if (extension.handshakeType != handshakeType) {
- hm.handshakeContext.conContext.fatal(
- Alert.UNSUPPORTED_EXTENSION,
- "extension (" + extId + ") should not be " +
- "presented in " + handshakeType.name);
- }
+ if (extension.handshakeType != handshakeType) {
+ hm.handshakeContext.conContext.fatal(
+ Alert.UNSUPPORTED_EXTENSION,
+ "extension (" + extId + ") should not be " +
+ "presented in " + handshakeType.name);
+ }
- byte[] extData = new byte[extLen];
- m.get(extData);
- extMap.put(extension, extData);
- if (logMap != null) {
- logMap.put(extId, extData);
+ byte[] extData = new byte[extLen];
+ m.get(extData);
+ extMap.put(extension, extData);
+ if (logMap != null) {
+ logMap.put(extId, extData);
+ }
+
+ isSupported = true;
+ break;
}
-
- isSupported = true;
- break;
}
if (!isSupported) {
--- a/src/java.base/unix/classes/java/io/UnixFileSystem.java Mon Aug 27 16:01:38 2018 -0400
+++ b/src/java.base/unix/classes/java/io/UnixFileSystem.java Mon Aug 27 16:02:55 2018 -0400
@@ -44,6 +44,8 @@
colon = props.getProperty("path.separator").charAt(0);
javaHome = StaticProperty.javaHome();
userDir = StaticProperty.userDir();
+ cache = useCanonCaches ? new ExpiringCache() : null;
+ javaHomePrefixCache = useCanonPrefixCache ? new ExpiringCache() : null;
}
@@ -145,11 +147,11 @@
// same directory, and must not create results differing from the true
// canonicalization algorithm in canonicalize_md.c. For this reason the
// prefix cache is conservative and is not used for complex path names.
- private ExpiringCache cache = new ExpiringCache();
+ private final ExpiringCache cache;
// On Unix symlinks can jump anywhere in the file system, so we only
// treat prefixes in java.home as trusted and cacheable in the
// canonicalization algorithm
- private ExpiringCache javaHomePrefixCache = new ExpiringCache();
+ private final ExpiringCache javaHomePrefixCache;
public String canonicalize(String path) throws IOException {
if (!useCanonCaches) {
@@ -158,7 +160,7 @@
String res = cache.get(path);
if (res == null) {
String dir = null;
- String resDir = null;
+ String resDir;
if (useCanonPrefixCache) {
// Note that this can cause symlinks that should
// be resolved to a destination directory to be
@@ -266,8 +268,12 @@
// (i.e., only remove/update affected entries) but probably
// not worth it since these entries expire after 30 seconds
// anyway.
- cache.clear();
- javaHomePrefixCache.clear();
+ if (useCanonCaches) {
+ cache.clear();
+ }
+ if (useCanonPrefixCache) {
+ javaHomePrefixCache.clear();
+ }
return delete0(f);
}
private native boolean delete0(File f);
@@ -279,8 +285,12 @@
// (i.e., only remove/update affected entries) but probably
// not worth it since these entries expire after 30 seconds
// anyway.
- cache.clear();
- javaHomePrefixCache.clear();
+ if (useCanonCaches) {
+ cache.clear();
+ }
+ if (useCanonPrefixCache) {
+ javaHomePrefixCache.clear();
+ }
return rename0(f1, f2);
}
private native boolean rename0(File f1, File f2);
--- a/src/java.base/windows/classes/java/io/WinNTFileSystem.java Mon Aug 27 16:01:38 2018 -0400
+++ b/src/java.base/windows/classes/java/io/WinNTFileSystem.java Mon Aug 27 16:02:55 2018 -0400
@@ -51,6 +51,8 @@
semicolon = props.getProperty("path.separator").charAt(0);
altSlash = (this.slash == '\\') ? '/' : '\\';
userDir = normalize(props.getProperty("user.dir"));
+ cache = useCanonCaches ? new ExpiringCache() : null;
+ prefixCache = useCanonPrefixCache ? new ExpiringCache() : null;
}
private boolean isSlash(char c) {
@@ -387,8 +389,8 @@
// same directory, and must not create results differing from the true
// canonicalization algorithm in canonicalize_md.c. For this reason the
// prefix cache is conservative and is not used for complex path names.
- private ExpiringCache cache = new ExpiringCache();
- private ExpiringCache prefixCache = new ExpiringCache();
+ private final ExpiringCache cache;
+ private final ExpiringCache prefixCache;
@Override
public String canonicalize(String path) throws IOException {
@@ -568,8 +570,12 @@
// (i.e., only remove/update affected entries) but probably
// not worth it since these entries expire after 30 seconds
// anyway.
- cache.clear();
- prefixCache.clear();
+ if (useCanonCaches) {
+ cache.clear();
+ }
+ if (useCanonPrefixCache) {
+ prefixCache.clear();
+ }
return delete0(f);
}
@@ -582,8 +588,12 @@
// (i.e., only remove/update affected entries) but probably
// not worth it since these entries expire after 30 seconds
// anyway.
- cache.clear();
- prefixCache.clear();
+ if (useCanonCaches) {
+ cache.clear();
+ }
+ if (useCanonPrefixCache) {
+ prefixCache.clear();
+ }
return rename0(f1, f2);
}
--- a/src/java.logging/share/classes/java/util/logging/Level.java Mon Aug 27 16:01:38 2018 -0400
+++ b/src/java.logging/share/classes/java/util/logging/Level.java Mon Aug 27 16:02:55 2018 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -610,10 +610,7 @@
}
private static void registerWithClassLoader(Level customLevel) {
- PrivilegedAction<ClassLoader> pa =
- () -> customLevel.getClass().getClassLoader();
- PrivilegedAction<String> pn = customLevel.getClass()::getName;
- final String name = AccessController.doPrivileged(pn);
+ PrivilegedAction<ClassLoader> pa = customLevel.getClass()::getClassLoader;
final ClassLoader cl = AccessController.doPrivileged(pa);
CUSTOM_LEVEL_CLV.computeIfAbsent(cl, (c, v) -> new ArrayList<>())
.add(customLevel);
@@ -624,19 +621,10 @@
// the mirroredLevel object is always added to the list
// before the custom Level instance
KnownLevel o = new KnownLevel(l);
- List<KnownLevel> list = nameToLevels.get(l.name);
- if (list == null) {
- list = new ArrayList<>();
- nameToLevels.put(l.name, list);
- }
- list.add(o);
-
- list = intToLevels.get(l.value);
- if (list == null) {
- list = new ArrayList<>();
- intToLevels.put(l.value, list);
- }
- list.add(o);
+ nameToLevels.computeIfAbsent(l.name, (k) -> new ArrayList<>())
+ .add(o);
+ intToLevels.computeIfAbsent(l.value, (k) -> new ArrayList<>())
+ .add(o);
// keep the custom level reachable from its class loader
// This will ensure that custom level values are not GC'ed
--- a/src/java.smartcardio/share/classes/sun/security/smartcardio/ChannelImpl.java Mon Aug 27 16:01:38 2018 -0400
+++ b/src/java.smartcardio/share/classes/sun/security/smartcardio/ChannelImpl.java Mon Aug 27 16:02:55 2018 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -188,7 +188,7 @@
byte[] response = SCardTransmit
(card.cardId, card.protocol, command, 0, n);
int rn = response.length;
- if (getresponse && (rn >= 2)) {
+ if (getresponse && (rn >= 2) && (n >= 1)) {
// see ISO 7816/2005, 5.1.3
if ((rn == 2) && (response[0] == 0x6c)) {
// Resend command using SW2 as short Le field
@@ -201,6 +201,11 @@
if (rn > 2) {
result = concat(result, response, rn - 2);
}
+ if (command.length < 5) {
+ byte cla = command[0];
+ command = new byte[5];
+ command[0] = cla;
+ }
command[1] = (byte)0xC0;
command[2] = 0;
command[3] = 0;
@@ -208,7 +213,6 @@
n = 5;
continue;
}
-
}
result = concat(result, response, rn);
break;
--- a/src/java.xml/share/classes/javax/xml/validation/Validator.java Mon Aug 27 16:01:38 2018 -0400
+++ b/src/java.xml/share/classes/javax/xml/validation/Validator.java Mon Aug 27 16:02:55 2018 -0400
@@ -214,7 +214,7 @@
*
* @throws IllegalArgumentException
* If the {@code Result} type doesn't match the
- * {@code Source} type of if the {@code Source}
+ * {@code Source} type or if the {@code Source}
* is an XML artifact that the implementation cannot
* validate (for example, a processing instruction).
* @throws SAXException
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java Mon Aug 27 16:01:38 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java Mon Aug 27 16:02:55 2018 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -539,7 +539,13 @@
}
nameSimplifier.addUsage(t.tsym);
visit(t.getTypeArguments());
- if (t.getEnclosingType() != Type.noType)
+ Type enclosingType;
+ try {
+ enclosingType = t.getEnclosingType();
+ } catch (CompletionFailure cf) {
+ return null;
+ }
+ if (enclosingType != Type.noType)
visit(t.getEnclosingType());
return null;
}
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/x86/LinuxX86CFrame.java Mon Aug 27 16:01:38 2018 -0400
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/x86/LinuxX86CFrame.java Mon Aug 27 16:02:55 2018 -0400
@@ -55,7 +55,15 @@
public CFrame sender(ThreadProxy thread) {
X86ThreadContext context = (X86ThreadContext) thread.getContext();
- Address esp = context.getRegisterAsAddress(X86ThreadContext.ESP);
+ /*
+ * Native code fills in the stack pointer register value using index
+ * X86ThreadContext.SP.
+ * See file LinuxDebuggerLocal.c macro REG_INDEX(reg).
+ *
+ * Be sure to use SP, or UESP which is aliased to SP in Java code,
+ * for the frame pointer validity check.
+ */
+ Address esp = context.getRegisterAsAddress(X86ThreadContext.SP);
if ( (ebp == null) || ebp.lessThan(esp) ) {
return null;
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windows/x86/WindowsX86CFrame.java Mon Aug 27 16:01:38 2018 -0400
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windows/x86/WindowsX86CFrame.java Mon Aug 27 16:02:55 2018 -0400
@@ -46,7 +46,15 @@
public CFrame sender(ThreadProxy thread) {
X86ThreadContext context = (X86ThreadContext) thread.getContext();
- Address esp = context.getRegisterAsAddress(X86ThreadContext.ESP);
+ /*
+ * Native code fills in the stack pointer register value using index
+ * X86ThreadContext.SP.
+ * See file sawindbg.cpp macro REG_INDEX(x).
+ *
+ * Be sure to use SP, or UESP which is aliased to SP in Java code,
+ * for the frame pointer validity check.
+ */
+ Address esp = context.getRegisterAsAddress(X86ThreadContext.SP);
if ( (ebp == null) || ebp.lessThan(esp) ) {
return null;
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Symbol.java Mon Aug 27 16:01:38 2018 -0400
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Symbol.java Mon Aug 27 16:02:55 2018 -0400
@@ -80,15 +80,16 @@
// _identity_hash is a short
private static CIntegerField idHash;
- public int identityHash() {
+ public long identityHash() {
long addr_value = getAddress().asLongValue();
- int addr_bits = (int)(addr_value >> (VM.getVM().getLogMinObjAlignmentInBytes() + 3));
+ long addr_bits =
+ (addr_value >> (VM.getVM().getLogMinObjAlignmentInBytes() + 3)) & 0xffffffffL;
int length = (int)getLength();
int byte0 = getByteAt(0);
int byte1 = getByteAt(1);
- int id_hash = (int)(0xffff & idHash.getValue(this.addr));
- return id_hash |
- ((addr_bits ^ (length << 8) ^ ((byte0 << 8) | byte1)) << 16);
+ long id_hash = 0xffffL & (long)idHash.getValue(this.addr);
+ return (id_hash |
+ ((addr_bits ^ (length << 8) ^ ((byte0 << 8) | byte1)) << 16)) & 0xffffffffL;
}
public boolean equals(byte[] modUTF8Chars) {
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/Hashtable.java Mon Aug 27 16:01:38 2018 -0400
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/Hashtable.java Mon Aug 27 16:02:55 2018 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -49,8 +49,8 @@
return HashtableEntry.class;
}
- public int computeHash(Symbol name) {
- return (int) name.identityHash();
+ public long computeHash(Symbol name) {
+ return name.identityHash();
}
public int hashToIndex(long fullHash) {
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodDataAccessor.java Mon Aug 27 16:01:38 2018 -0400
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodDataAccessor.java Mon Aug 27 16:02:55 2018 -0400
@@ -1,3 +1,25 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
package jdk.vm.ci.hotspot;
import jdk.vm.ci.meta.JavaMethodProfile;
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/OldObjectSample.java Mon Aug 27 16:01:38 2018 -0400
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/OldObjectSample.java Mon Aug 27 16:02:55 2018 -0400
@@ -1,3 +1,28 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
package jdk.jfr.internal;
import java.util.HashMap;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/gtest/utilities/test_singleWriterSynchronizer.cpp Mon Aug 27 16:02:55 2018 -0400
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
+#include "runtime/orderAccess.hpp"
+#include "runtime/os.hpp"
+#include "runtime/thread.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/globalCounter.inline.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/ostream.hpp"
+#include "utilities/singleWriterSynchronizer.hpp"
+#include "threadHelper.inline.hpp"
+#include "unittest.hpp"
+
+class SingleWriterSynchronizerTestReader : public JavaTestThread {
+ SingleWriterSynchronizer* _synchronizer;
+ volatile uintx* _synchronized_value;
+ volatile int* _continue_running;
+
+ static const uint reader_iterations = 10;
+
+public:
+ SingleWriterSynchronizerTestReader(Semaphore* post,
+ SingleWriterSynchronizer* synchronizer,
+ volatile uintx* synchronized_value,
+ volatile int* continue_running) :
+ JavaTestThread(post),
+ _synchronizer(synchronizer),
+ _synchronized_value(synchronized_value),
+ _continue_running(continue_running)
+ {}
+
+ virtual void main_run() {
+ uintx iterations = 0;
+ while (OrderAccess::load_acquire(_continue_running) != 0) {
+ ++iterations;
+ SingleWriterSynchronizer::CriticalSection cs(_synchronizer);
+ uintx value = OrderAccess::load_acquire(_synchronized_value);
+ for (uint i = 0; i < reader_iterations; ++i) {
+ uintx new_value = OrderAccess::load_acquire(_synchronized_value);
+ // A reader can see either the value it first read after
+ // entering the critical section, or that value + 1. No other
+ // values are possible.
+ if (value != new_value) {
+ ASSERT_EQ((value + 1), new_value);
+ }
+ }
+ }
+ tty->print_cr("reader iterations: " UINTX_FORMAT, iterations);
+ }
+};
+
+class SingleWriterSynchronizerTestWriter : public JavaTestThread {
+ SingleWriterSynchronizer* _synchronizer;
+ volatile uintx* _synchronized_value;
+ volatile int* _continue_running;
+
+public:
+ SingleWriterSynchronizerTestWriter(Semaphore* post,
+ SingleWriterSynchronizer* synchronizer,
+ volatile uintx* synchronized_value,
+ volatile int* continue_running) :
+ JavaTestThread(post),
+ _synchronizer(synchronizer),
+ _synchronized_value(synchronized_value),
+ _continue_running(continue_running)
+ {}
+
+ virtual void main_run() {
+ while (OrderAccess::load_acquire(_continue_running) != 0) {
+ ++*_synchronized_value;
+ _synchronizer->synchronize();
+ }
+ tty->print_cr("writer iterations: " UINTX_FORMAT, *_synchronized_value);
+ }
+};
+
+const uint nreaders = 5;
+const uint milliseconds_to_run = 3000;
+
+TEST_VM(TestSingleWriterSynchronizer, stress) {
+ Semaphore post;
+ SingleWriterSynchronizer synchronizer;
+ volatile uintx synchronized_value = 0;
+ volatile int continue_running = 1;
+
+ JavaTestThread* readers[nreaders] = {};
+ for (uint i = 0; i < nreaders; ++i) {
+ readers[i] = new SingleWriterSynchronizerTestReader(&post,
+ &synchronizer,
+ &synchronized_value,
+ &continue_running);
+ readers[i]->doit();
+ }
+
+ JavaTestThread* writer =
+ new SingleWriterSynchronizerTestWriter(&post,
+ &synchronizer,
+ &synchronized_value,
+ &continue_running);
+
+ writer->doit();
+
+ tty->print_cr("Stressing synchronizer for %u ms", milliseconds_to_run);
+ {
+ ThreadInVMfromNative invm(JavaThread::current());
+ os::sleep(Thread::current(), milliseconds_to_run, true);
+ }
+ continue_running = 0;
+ for (uint i = 0; i < nreaders + 1; ++i) {
+ post.wait();
+ }
+}
--- a/test/hotspot/jtreg/ProblemList-cds-mode.txt Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/ProblemList-cds-mode.txt Mon Aug 27 16:02:55 2018 -0400
@@ -27,5 +27,3 @@
#
#############################################################################
-serviceability/sa/TestInstanceKlassSize.java 8204308 generic-all
-serviceability/sa/TestInstanceKlassSizeForInterface.java 8204308 generic-all
--- a/test/hotspot/jtreg/ProblemList.txt Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/ProblemList.txt Mon Aug 27 16:02:55 2018 -0400
@@ -83,6 +83,7 @@
runtime/CompressedOops/UseCompressedOops.java 8079353 generic-all
runtime/RedefineTests/RedefineRunningMethods.java 8208778 macosx-x64
runtime/SharedArchiveFile/SASymbolTableTest.java 8193639 solaris-all
+runtime/MemberName/MemberNameLeak.java 8209844 generic-all
#############################################################################
@@ -91,6 +92,7 @@
serviceability/sa/ClhsdbAttach.java 8193639 solaris-all
serviceability/sa/ClhsdbCDSCore.java 8193639 solaris-all
serviceability/sa/ClhsdbCDSJstackPrintAll.java 8193639 solaris-all
+serviceability/sa/CDSJMapClstats.java 8193639 solaris-all
serviceability/sa/ClhsdbField.java 8193639 solaris-all
serviceability/sa/ClhsdbFindPC.java 8193639 solaris-all
serviceability/sa/ClhsdbFlags.java 8193639 solaris-all
@@ -179,7 +181,6 @@
vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted003/TestDescription.java 6606767 generic-all
vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted004/TestDescription.java 7013634,6606767 generic-all
vmTestbase/nsk/jvmti/ThreadStart/threadstart001/TestDescription.java 8016181 generic-all
-vmTestbase/nsk/jvmti/ThreadStart/threadstart003/TestDescription.java 8034084 generic-all
vmTestbase/nsk/jvmti/scenarios/extension/EX03/ex03t001/TestDescription.java 8173658 generic-all
vmTestbase/nsk/jvmti/scenarios/hotswap/HS102/hs102t002/TestDescription.java 8204506,8203350 generic-all
vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t001/hs204t001.java 6813266 generic-all
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/c2/SubsumingLoadsCauseFlagSpill.java Mon Aug 27 16:02:55 2018 -0400
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018, Red Hat, Inc. 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 8209639
+ * @summary assert failure in coalesce.cpp: attempted to spill a non-spillable item
+ *
+ * @run main/othervm -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,SubsumingLoadsCauseFlagSpill::not_inlined -Xmx1024m SubsumingLoadsCauseFlagSpill
+ *
+ */
+
+public class SubsumingLoadsCauseFlagSpill {
+ private static Object field;
+ private static boolean do_throw;
+ private static volatile boolean barrier;
+
+ public static void main(String[] args) {
+ for (int i = 0; i < 20_000; i++) {
+ do_throw = true;
+ field = null;
+ test(0);
+ do_throw = false;
+ field = new Object();
+ test(0);
+ }
+ }
+
+ private static float test(float f) {
+ Object v = null;
+ try {
+ not_inlined();
+ v = field;
+ } catch (MyException me) {
+ v = field;
+ barrier = true;
+ }
+ if (v == null) {
+ return f * f;
+ }
+ return f;
+ }
+
+ private static void not_inlined() throws MyException{
+ if (do_throw) {
+ throw new MyException();
+ }
+ }
+
+ private static class MyException extends Throwable {
+ }
+}
--- a/test/hotspot/jtreg/compiler/interpreter/TestVerifyStackAfterDeopt.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/compiler/interpreter/TestVerifyStackAfterDeopt.java Mon Aug 27 16:02:55 2018 -0400
@@ -25,8 +25,10 @@
/*
* @test TestVerifyStackAfterDeopt
* @bug 8148871
+ * @bug 8209825
* @summary Checks VerifyStack after deoptimization of array allocation slow call
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:TieredStopAtLevel=1
+ * -XX:MinTLABSize=1k -XX:TLABSize=1k
* -XX:+DeoptimizeALot -XX:+VerifyStack
* compiler.interpreter.TestVerifyStackAfterDeopt
*/
@@ -35,9 +37,11 @@
public class TestVerifyStackAfterDeopt {
- private void method(Object[] a) {
+ private long method(long l1, long l2, Object[] a) {
+ return l1 + l2;
+ }
- }
+ private long result[] = new long[1];
private void test() {
// For the array allocation, C1 emits a slow call into the runtime
@@ -45,7 +49,7 @@
// The VerifyStack code then gets confused because the following
// bytecode instruction is an invoke and the interpreter oop map
// generator reports the oop map after execution of that invoke.
- method(new Object[0]);
+ this.result[0] = method(1L, 2L, new Object[0]);
}
public static void main(String[] args) {
--- a/test/hotspot/jtreg/compiler/intrinsics/object/TestClone.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/compiler/intrinsics/object/TestClone.java Mon Aug 27 16:02:55 2018 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,7 @@
* @library /test/lib
*
* @run main/othervm -XX:-TieredCompilation -Xbatch
- * -XX:CompileCommand=compileonly,compiler.intrinsics.object.TestClone::f
+ * -XX:CompileCommand=compileonly,compiler.intrinsics.object.TestClone::test*
* compiler.intrinsics.object.TestClone
*/
@@ -37,6 +37,43 @@
import jdk.test.lib.Asserts;
+abstract class MyAbstract {
+
+ public Object myClone1() throws CloneNotSupportedException {
+ return this.clone();
+ }
+
+ public Object myClone2() throws CloneNotSupportedException {
+ return this.clone();
+ }
+
+ public Object myClone3() throws CloneNotSupportedException {
+ return this.clone();
+ }
+}
+
+class MyClass1 extends MyAbstract {
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+}
+
+class MyClass2 extends MyAbstract {
+
+}
+
+class MyClass3 extends MyAbstract implements Cloneable {
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+}
+
+class MyClass4 extends MyAbstract implements Cloneable {
+
+}
+
public class TestClone implements Cloneable {
static class A extends TestClone {}
static class B extends TestClone {
@@ -56,29 +93,70 @@
}
static TestClone a = new A(), b = new B(), c = new C(), d = new D();
- public static Object f(TestClone o) throws CloneNotSupportedException {
+ public static Object test1(TestClone o) throws CloneNotSupportedException {
// Polymorphic call site: >90% Object::clone / <10% other methods
return o.clone();
}
+ public static void test2(MyAbstract obj, boolean shouldThrow) throws Exception {
+ try {
+ obj.myClone1();
+ } catch (Exception e) {
+ return; // Expected
+ }
+ Asserts.assertFalse(shouldThrow, "No exception thrown");
+ }
+
+ public static void test3(MyAbstract obj, boolean shouldThrow) throws Exception {
+ try {
+ obj.myClone2();
+ } catch (Exception e) {
+ return; // Expected
+ }
+ Asserts.assertFalse(shouldThrow, "No exception thrown");
+ }
+
+ public static void test4(MyAbstract obj, boolean shouldThrow) throws Exception {
+ try {
+ obj.myClone3();
+ } catch (Exception e) {
+ return; // Expected
+ }
+ Asserts.assertFalse(shouldThrow, "No exception thrown");
+ }
+
public static void main(String[] args) throws Exception {
TestClone[] params1 = {a, a, a, a, a, a, a, a, a, a, a,
a, a, a, a, a, a, a, a, a, a, a,
a, a, a, a, a, a, a, a, a, a, a,
b, c, d};
+ MyClass1 obj1 = new MyClass1();
+ MyClass2 obj2 = new MyClass2();
+ MyClass3 obj3 = new MyClass3();
+ MyClass4 obj4 = new MyClass4();
+
for (int i = 0; i < 15000; i++) {
- f(params1[i % params1.length]);
+ test1(params1[i % params1.length]);
+
+ test2(obj1, true);
+ test2(obj2, true);
+
+ test3(obj3, false);
+ test3(obj2, true);
+
+ test4(obj3, false);
+ test4(obj4, false);
}
- Asserts.assertTrue(f(a) != a);
- Asserts.assertTrue(f(b) == b);
- Asserts.assertTrue(f(c) == c);
- Asserts.assertTrue(f(d) == d);
+ Asserts.assertTrue(test1(a) != a);
+ Asserts.assertTrue(test1(b) == b);
+ Asserts.assertTrue(test1(c) == c);
+ Asserts.assertTrue(test1(d) == d);
try {
- f(null);
- throw new AssertionError("");
+ test1(null);
+ throw new AssertionError("No exception thrown");
} catch (NullPointerException e) { /* expected */ }
System.out.println("TEST PASSED");
--- a/test/hotspot/jtreg/runtime/appcds/HelloExtTest.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/HelloExtTest.java Mon Aug 27 16:02:55 2018 -0400
@@ -52,7 +52,7 @@
TestCommon.dump(appJar,
TestCommon.list("javax/annotation/processing/FilerException", "[Ljava/lang/Comparable;"),
- bootClassPath, "-verbose:class");
+ bootClassPath);
String prefix = ".class.load. ";
String class_pattern = ".*LambdaForm[$]MH[/][0123456789].*";
@@ -60,12 +60,12 @@
String pattern = prefix + class_pattern + suffix;
TestCommon.run("-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
- "-cp", appJar, bootClassPath, "-verbose:class", "HelloExt")
+ "-cp", appJar, bootClassPath, "-Xlog:class+load", "HelloExt")
.assertNormalExit(output -> output.shouldNotMatch(pattern));
TestCommon.run("-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
- "-cp", appJar, bootClassPath, "-verbose:class",
+ "-cp", appJar, bootClassPath, "-Xlog:class+load",
"-XX:+PrintSharedArchiveAndExit", "-XX:+PrintSharedDictionary",
"HelloExt")
.assertNormalExit(output -> output.shouldNotMatch(class_pattern));
--- a/test/hotspot/jtreg/runtime/appcds/OldClassTest.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/OldClassTest.java Mon Aug 27 16:02:55 2018 -0400
@@ -67,7 +67,6 @@
TestCommon.run(
"-cp", jar,
- "-verbose:class",
"Hello")
.assertNormalExit("Hello Unicode world (Old)");
@@ -79,7 +78,6 @@
TestCommon.run(
"-cp", classpath,
- "-verbose:class",
"Hello")
.assertNormalExit("Hello Unicode world (Old)");
}
--- a/test/hotspot/jtreg/runtime/appcds/ProhibitedPackage.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/ProhibitedPackage.java Mon Aug 27 16:02:55 2018 -0400
@@ -79,20 +79,20 @@
// -Xshare:on
TestCommon.run(
"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
- "-cp", appJar, "-Xlog:class+load=info", "ProhibitedHelper")
+ "-cp", appJar, "ProhibitedHelper")
.assertNormalExit("Prohibited package name: java.lang");
// -Xshare:auto
output = TestCommon.execAuto(
"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
- "-cp", appJar, "-Xlog:class+load=info", "ProhibitedHelper");
+ "-cp", appJar, "ProhibitedHelper");
CDSOptions opts = (new CDSOptions()).setXShareMode("auto");
TestCommon.checkExec(output, opts, "Prohibited package name: java.lang");
// -Xshare:off
output = TestCommon.execOff(
"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
- "-cp", appJar, "-Xlog:class+load=info", "ProhibitedHelper");
+ "-cp", appJar, "ProhibitedHelper");
output.shouldContain("Prohibited package name: java.lang");
}
}
--- a/test/hotspot/jtreg/runtime/appcds/ProtectionDomain.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/ProtectionDomain.java Mon Aug 27 16:02:55 2018 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -57,16 +57,16 @@
OutputAnalyzer output;
// First class is loaded from CDS, second class is loaded from JAR
- output = TestCommon.exec(appJar, "-verbose:class", "ProtDomain");
+ output = TestCommon.exec(appJar, "ProtDomain");
TestCommon.checkExec(output, "Protection Domains match");
// First class is loaded from JAR, second class is loaded from CDS
- output = TestCommon.exec(appJar, "-verbose:class", "ProtDomainB");
+ output = TestCommon.exec(appJar, "ProtDomainB");
TestCommon.checkExec(output, "Protection Domains match");
// Test ProtectionDomain for application and extension module classes from the
// "modules" jimage
- output = TestCommon.exec(appJar, "-verbose:class", "JimageClassProtDomain");
+ output = TestCommon.exec(appJar, "JimageClassProtDomain");
output.shouldNotContain("Failed: Protection Domains do not match");
}
}
--- a/test/hotspot/jtreg/runtime/appcds/cacheObject/RedefineClassTest.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/RedefineClassTest.java Mon Aug 27 16:02:55 2018 -0400
@@ -34,7 +34,7 @@
* RedefineClassApp
* InstrumentationClassFileTransformer
* InstrumentationRegisterClassFileTransformer
- * @run main/othervm RedefineClassTest
+ * @run main RedefineClassTest
*/
import com.sun.tools.attach.VirtualMachine;
@@ -89,7 +89,7 @@
bootCP,
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+WhiteBoxAPI",
- "-Xlog:gc+region=trace,cds=info",
+ "-Xlog:cds=info",
agentCmdArg,
"RedefineClassApp", bootJar, appJar);
out.reportDiagnosticSummary();
--- a/test/hotspot/jtreg/runtime/appcds/javaldr/ArrayTest.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/javaldr/ArrayTest.java Mon Aug 27 16:02:55 2018 -0400
@@ -57,7 +57,7 @@
String bootClassPath = "-Xbootclasspath/a:" + whiteBoxJar;
// create an archive containing array classes
- OutputAnalyzer output = TestCommon.dump(appJar, TestCommon.list(arrayClasses), bootClassPath, "-verbose:class");
+ OutputAnalyzer output = TestCommon.dump(appJar, TestCommon.list(arrayClasses), bootClassPath);
// we currently don't support array classes during CDS dump
output.shouldContain("Preload Warning: Cannot find [Ljava/lang/Comparable;")
.shouldContain("Preload Warning: Cannot find [I")
@@ -70,7 +70,6 @@
argsList.add("-cp");
argsList.add(appJar);
argsList.add(bootClassPath);
- argsList.add("-verbose:class");
argsList.add("ArrayTestHelper");
// the following are input args to the ArrayTestHelper.
// skip checking array classes during run time
--- a/test/hotspot/jtreg/runtime/appcds/javaldr/GCDuringDump.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/javaldr/GCDuringDump.java Mon Aug 27 16:02:55 2018 -0400
@@ -56,7 +56,8 @@
String appJar =
ClassFileInstaller.writeJar("GCDuringDumpApp.jar", appClasses);
- String gcLog = "-Xlog:gc*=info,gc+region=trace,gc+alloc+region=debug";
+ String gcLog = Boolean.getBoolean("test.cds.verbose.gc") ?
+ "-Xlog:gc*=info,gc+region=trace,gc+alloc+region=debug" : "-showversion";
for (int i=0; i<2; i++) {
// i = 0 -- run without agent = no extra GCs
--- a/test/hotspot/jtreg/runtime/appcds/javaldr/GCDuringDumpTransformer.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/javaldr/GCDuringDumpTransformer.java Mon Aug 27 16:02:55 2018 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -28,13 +28,8 @@
import java.security.ProtectionDomain;
public class GCDuringDumpTransformer implements ClassFileTransformer {
- static int n = 0;
public byte[] transform(ClassLoader loader, String name, Class<?> classBeingRedefined,
ProtectionDomain pd, byte[] buffer) throws IllegalClassFormatException {
- n++;
-
- System.out.println("dump time loading: " + name + " in loader: " + loader);
- System.out.println("making garbage: " + n);
try {
makeGarbage();
} catch (Throwable t) {
@@ -43,7 +38,6 @@
Thread.sleep(200); // let GC to have a chance to run
} catch (Throwable t2) {}
}
- System.out.println("making garbage: done");
return null;
}
--- a/test/hotspot/jtreg/runtime/appcds/javaldr/GCSharedStringsDuringDump.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/javaldr/GCSharedStringsDuringDump.java Mon Aug 27 16:02:55 2018 -0400
@@ -62,7 +62,8 @@
String appJar =
ClassFileInstaller.writeJar("GCSharedStringsDuringDumpApp.jar", appClasses);
- String gcLog = "-Xlog:gc*=info,gc+region=trace,gc+alloc+region=debug";
+ String gcLog = Boolean.getBoolean("test.cds.verbose.gc") ?
+ "-Xlog:gc*=info,gc+region=trace,gc+alloc+region=debug" : "-showversion";
String sharedArchiveCfgFile =
System.getProperty("user.dir") + File.separator + "GCSharedStringDuringDump_gen.txt";
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddOpens.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddOpens.java Mon Aug 27 16:02:55 2018 -0400
@@ -87,7 +87,6 @@
// the class in the modular jar in the -cp won't be archived.
OutputAnalyzer output = TestCommon.createArchive(
destJar.toString(), appClasses,
- "-Xlog:class+load=trace",
"--module-path", moduleDir.toString(),
"-m", TEST_MODULE1);
TestCommon.checkDump(output);
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/ExportModule.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/ExportModule.java Mon Aug 27 16:02:55 2018 -0400
@@ -118,7 +118,6 @@
// the module in the --module-path
OutputAnalyzer output = TestCommon.createArchive(
appJar.toString(), appClasses,
- "-Xlog:class+load=trace",
"--module-path", moduleDir.toString(),
"--add-modules", TEST_MODULE2, MAIN_CLASS);
TestCommon.checkDump(output);
@@ -142,7 +141,6 @@
// unnmaed.
output = TestCommon.createArchive(
appJar2.toString(), appClasses2,
- "-Xlog:class+load=trace",
"--module-path", moduleDir.toString(),
"--add-modules", TEST_MODULE2,
"--add-exports", "org.astro/org.astro=ALL-UNNAMED",
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/JvmtiAddPath.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/JvmtiAddPath.java Mon Aug 27 16:02:55 2018 -0400
@@ -113,7 +113,6 @@
appJar,
TestCommon.list("JvmtiApp", "ExtraClass", MAIN_CLASS),
use_whitebox_jar,
- "-Xlog:class+load=trace",
modulePath);
TestCommon.checkDump(output);
@@ -143,7 +142,6 @@
output = TestCommon.createArchive(
appJar, TestCommon.list("JvmtiApp", "ExtraClass"),
use_whitebox_jar,
- "-Xlog:class+load=trace",
modulePath);
TestCommon.checkDump(output);
run(twoAppJars, modulePath,
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/MainModuleOnly.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/MainModuleOnly.java Mon Aug 27 16:02:55 2018 -0400
@@ -90,7 +90,6 @@
// the class in the modular jar in the -cp won't be archived.
OutputAnalyzer output = TestCommon.createArchive(
destJar.toString(), appClasses,
- "-Xlog:class+load=trace",
"--module-path", moduleDir.toString(),
"-m", TEST_MODULE1);
TestCommon.checkDump(output);
@@ -169,8 +168,7 @@
// run with the archive and the jar with modified timestamp.
// It should fail due to timestamp of the jar doesn't match the one
// used during dump time.
- TestCommon.run("-Xlog:class+load=trace",
- "-cp", destJar.toString(),
+ TestCommon.run("-cp", destJar.toString(),
"--module-path", moduleDir.toString(),
"-m", TEST_MODULE1)
.assertAbnormalExit(
--- a/test/hotspot/jtreg/runtime/appcds/jvmti/transformRelatedClasses/TransformRelatedClassesAppCDS.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jvmti/transformRelatedClasses/TransformRelatedClassesAppCDS.java Mon Aug 27 16:02:55 2018 -0400
@@ -188,7 +188,6 @@
TestCommon.run("-Xlog:class+load=info",
"-cp", appJar,
- "--add-opens=java.base/java.security=ALL-UNNAMED",
agentParam,
"CustomLoaderApp",
customJar, loaderType, child)
--- a/test/hotspot/jtreg/runtime/appcds/sharedStrings/IncompatibleOptions.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/sharedStrings/IncompatibleOptions.java Mon Aug 27 16:02:55 2018 -0400
@@ -29,15 +29,11 @@
* @requires vm.cds.archived.java.heap
* @requires (vm.gc=="null")
* @library /test/lib /test/hotspot/jtreg/runtime/appcds
- * @modules java.base/jdk.internal.misc
- * @modules java.management
- * jdk.jartool/sun.tools.jar
+ * @modules jdk.jartool/sun.tools.jar
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
* @build HelloString
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. IncompatibleOptions
- * @run main/othervm -XX:+UseStringDeduplication -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. IncompatibleOptions
- * @run main/othervm -XX:-CompactStrings -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. IncompatibleOptions
*/
import jdk.test.lib.Asserts;
@@ -59,8 +55,10 @@
"The shared archive file's CompactStrings setting .* does not equal the current CompactStrings setting";
static String appJar;
+ static String[] globalVmOptions;
public static void main(String[] args) throws Exception {
+ globalVmOptions = args; // specified by "@run main" in IncompatibleOptions_*.java
appJar = JarBuilder.build("IncompatibleOptions", "HelloString");
// Uncompressed OOPs
@@ -116,14 +114,16 @@
System.out.println("Testcase: " + testCaseNr);
OutputAnalyzer output = TestCommon.dump(appJar, TestCommon.list("Hello"),
- "-XX:+UseCompressedOops",
- collectorOption,
- "-XX:SharedArchiveConfigFile=" + TestCommon.getSourceFile("SharedStringsBasic.txt"),
- "-Xlog:cds,cds+hashtables",
- extraOption);
+ TestCommon.concat(globalVmOptions,
+ "-XX:+UseCompressedOops",
+ collectorOption,
+ "-XX:SharedArchiveConfigFile=" + TestCommon.getSourceFile("SharedStringsBasic.txt"),
+ "-Xlog:cds,cds+hashtables",
+ extraOption));
- if (expectedWarning != null)
+ if (expectedWarning != null) {
output.shouldContain(expectedWarning);
+ }
if (expectedToFail) {
Asserts.assertNE(output.getExitValue(), 0,
@@ -140,19 +140,25 @@
// needed, otherwise system considers empty extra option as a
// main class param, and fails with "Could not find or load main class"
if (!extraOption.isEmpty()) {
- output = TestCommon.exec(appJar, "-XX:+UseCompressedOops",
- collectorOption, "-Xlog:cds", extraOption, "HelloString");
+ output = TestCommon.exec(appJar,
+ TestCommon.concat(globalVmOptions,
+ "-XX:+UseCompressedOops",
+ collectorOption, "-Xlog:cds", extraOption, "HelloString"));
} else {
- output = TestCommon.exec(appJar, "-XX:+UseCompressedOops",
- collectorOption, "-Xlog:cds", "HelloString");
+ output = TestCommon.exec(appJar,
+ TestCommon.concat(globalVmOptions,
+ "-XX:+UseCompressedOops",
+ collectorOption, "-Xlog:cds", "HelloString"));
}
- if (expectedWarning != null)
+ if (expectedWarning != null) {
output.shouldMatch(expectedWarning);
+ }
- if (expectedToFail)
+ if (expectedToFail) {
Asserts.assertNE(output.getExitValue(), 0);
- else
+ } else {
SharedStringsUtils.checkExec(output);
+ }
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/sharedStrings/IncompatibleOptions_noCompactStrings.java Mon Aug 27 16:02:55 2018 -0400
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ * @test
+ * @summary Test options that are incompatible with use of shared strings
+ * Also test mismatch in oops encoding between dump time and run time
+ * @requires vm.cds.archived.java.heap
+ * @requires (vm.gc=="null")
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.jartool/sun.tools.jar
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @build HelloString
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. IncompatibleOptions -XX:-CompactStrings
+ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/sharedStrings/IncompatibleOptions_stringDedup.java Mon Aug 27 16:02:55 2018 -0400
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ * @test
+ * @summary Test options that are incompatible with use of shared strings
+ * Also test mismatch in oops encoding between dump time and run time
+ * @requires vm.cds.archived.java.heap
+ * @requires (vm.gc=="null")
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.jartool/sun.tools.jar
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @build HelloString
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. IncompatibleOptions -XX:+UseStringDeduplication
+ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/logging/RedefineClasses.java Mon Aug 27 16:02:55 2018 -0400
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 8197901 8209758
+ * @summary Redefine classes with enabling logging to verify Klass:external_name() during GC.
+ * @comment This test is simplified version of runtime/RedefineTests/RedefineRunningMethods.java.
+ * @library /test/lib
+ * @modules java.compiler
+ * java.instrument
+ * jdk.jartool/sun.tools.jar
+ * @run main RedefineClassHelper
+ * @run main/othervm -Xmx256m -XX:MaxMetaspaceSize=64m -javaagent:redefineagent.jar -Xlog:all=trace:file=all.log RedefineClasses
+ */
+
+// package access top-level class to avoid problem with RedefineClassHelper
+// and nested types.
+class RedefineClasses_B {
+ public static void test() {
+ }
+}
+
+public class RedefineClasses {
+ static Object[] obj = new Object[20];
+ public static String newB =
+ "class RedefineClasses_B {" +
+ " public static void test() { " +
+ " }" +
+ "}";
+
+ public static void main(String[] args) throws Exception {
+ RedefineClassHelper.redefineClass(RedefineClasses_B.class, newB);
+ RedefineClasses_B.test();
+ for (int i = 0; i < 20 ; i++) {
+ obj[i] = new byte[1024 * 1024];
+ System.gc();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/serviceability/sa/CDSJMapClstats.java Mon Aug 27 16:02:55 2018 -0400
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8204308
+ * @summary Test the jhsdb jmap -clstats command with CDS enabled
+ * @requires vm.hasSAandCanAttach & vm.cds
+ * @library /test/lib
+ * @run main/othervm/timeout=2400 CDSJMapClstats
+ */
+
+import java.util.List;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+import jdk.test.lib.cds.CDSTestUtils;
+import jdk.test.lib.cds.CDSOptions;
+import jdk.test.lib.apps.LingeredApp;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.JDKToolLauncher;
+
+public class CDSJMapClstats {
+
+ private static void runClstats(long lingeredAppPid) throws Exception {
+
+ JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jhsdb");
+ launcher.addToolArg("jmap");
+ launcher.addToolArg("--clstats");
+ launcher.addToolArg("--pid");
+ launcher.addToolArg(Long.toString(lingeredAppPid));
+
+ ProcessBuilder processBuilder = new ProcessBuilder();
+ processBuilder.command(launcher.getCommand());
+ System.out.println(
+ processBuilder.command().stream().collect(Collectors.joining(" ")));
+
+ OutputAnalyzer SAOutput = ProcessTools.executeProcess(processBuilder);
+ System.out.println(SAOutput.getOutput());
+ SAOutput.shouldHaveExitValue(0);
+ SAOutput.shouldContain("BootClassLoader");
+ }
+
+
+ public static void main(String[] args) throws Exception {
+ System.out.println("Starting CDSJMapClstats test");
+ String sharedArchiveName = "ArchiveForCDSJMapClstats.jsa";
+ LingeredApp theApp = null;
+
+ try {
+ CDSOptions opts = (new CDSOptions()).setArchiveName(sharedArchiveName);
+ CDSTestUtils.createArchiveAndCheck(opts);
+
+ List<String> vmArgs = Arrays.asList(
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:SharedArchiveFile=" + sharedArchiveName,
+ "-Xshare:auto");
+ theApp = LingeredApp.startApp(vmArgs);
+ System.out.println("Started LingeredApp with pid " + theApp.getPid());
+ runClstats(theApp.getPid());
+ } catch (Exception ex) {
+ throw new RuntimeException("Test ERROR " + ex, ex);
+ } finally {
+ LingeredApp.stopApp(theApp);
+ }
+ System.out.println("Test PASSED");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/serviceability/sa/LingeredAppWithNativeMethod.java Mon Aug 27 16:02:55 2018 -0400
@@ -0,0 +1,74 @@
+
+/*
+ * 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 jdk.test.lib.apps.LingeredApp;
+
+public class LingeredAppWithNativeMethod extends LingeredApp {
+
+ public static final String THREAD_NAME = "NoFramePointerJNIFib";
+ private static final int UPPER_BOUND = 55;
+ private static final int LOWER_BOUND = 40;
+
+ static {
+ // JNI library compiled with no frame pointer info
+ System.loadLibrary("NoFramePointer");
+ }
+
+ public void callNative() {
+ // Call JNI code which does something compute
+ // intensive: fibonacci
+ // That is to ensure that the native bits run when
+ // jstack --mixed info is to be gathered.
+ // Results of fibonacci calculation from JNI are
+ // reported via callback(). That's where the process
+ // of calculating fibonacci restarts.
+ int num = (int) (Math.random() * UPPER_BOUND);
+ while (num < LOWER_BOUND) {
+ num = (int) (Math.random() * UPPER_BOUND);
+ }
+ System.out.print("fib(" + num + ") = ");
+ callJNI(this, num);
+ }
+
+ // Called from JNI library libNoFramePointer
+ private void callback(long val) {
+ System.out.println(val);
+ // Call native again so as to increase chances of
+ // being currently in JNI code when jstack --mixed
+ // runs.
+ callNative();
+ }
+
+ public static native void callJNI(Object target, int num);
+
+ public static void main(String[] args) {
+ LingeredAppWithNativeMethod app = new LingeredAppWithNativeMethod();
+ Thread fibonacci = new Thread(() -> {
+ app.callNative();
+ });
+ fibonacci.setName(THREAD_NAME);
+ fibonacci.start();
+ LingeredApp.main(args);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixed.java Mon Aug 27 16:02:55 2018 -0400
@@ -0,0 +1,187 @@
+/*
+ * 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.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import jdk.test.lib.JDKToolLauncher;
+import jdk.test.lib.Utils;
+import jdk.test.lib.apps.LingeredApp;
+import jdk.test.lib.process.OutputAnalyzer;
+
+/**
+ * @test
+ * @bug 8208091
+ * @requires (os.family == "linux") & (vm.hasSAandCanAttach)
+ * @library /test/lib
+ * @run main/othervm TestJhsdbJstackMixed
+ */
+public class TestJhsdbJstackMixed {
+
+ private static final int MAX_ITERATIONS = 20;
+ private static final String NATIVE_FUNCTION_NAME = "fib";
+ private static final String LINE_MATCHER_STR = ".*" + NATIVE_FUNCTION_NAME
+ + ".*";
+ private static final Pattern LINE_PATTERN = Pattern
+ .compile(LINE_MATCHER_STR);
+ private static final String HEX_STR_PATTERN = "0x([a-fA-F0-9]+)";
+ private static final String FIB_SPLIT_PATTERN = NATIVE_FUNCTION_NAME
+ + "\\s+\\+";
+ private static final Pattern HEX_PATTERN = Pattern.compile(HEX_STR_PATTERN);
+ private static final int ADDRESS_ALIGNMENT_X86 = 4;
+
+ /*
+ * UnmappedAddressException will be thrown iff:
+ * - The JNI code is being compiled with -fomit-frame-pointer AND
+ * - The JNI code is currently executing at address A = pc() + offset
+ * where A % ADDRESS_SIZE == 0.
+ *
+ * In the below example we have: pc() == f6401546, offset == 56,
+ * ADDRESS_SIZE == 4. Thus, A == F640159C which satisfies this condition.
+ *
+ * "NoFramePointerJNIFib" #11 prio=5 tid=0xa357bc00 nid=0x6de9 runnable [0xa365b000]
+ * java.lang.Thread.State: RUNNABLE
+ * JavaThread state: _thread_in_native
+ * 0xf6401546 fib + 0x56
+ */
+ private static boolean isFibAndAlignedAddress(List<String> lines) {
+ List<String> fibLines = findFibLines(lines);
+ System.out.println("DEBUG: " + fibLines);
+ // we're only interested in the first matched line.
+ if (fibLines.size() >= 1) {
+ String line = fibLines.get(0);
+ return isMatchLine(line);
+ }
+ return false;
+ }
+
+ private static boolean isMatchLine(String line) {
+ String[] tokens = line.split(FIB_SPLIT_PATTERN);
+ if (tokens.length != 2) {
+ return false; // NOT exactly two tokens, ignore.
+ }
+ String pcRaw = tokens[0].trim();
+ String offsetRaw = tokens[1].trim();
+ Matcher matcher = HEX_PATTERN.matcher(pcRaw);
+ long pcVal = 3;
+ boolean pcMatched = matcher.matches();
+ if (pcMatched) {
+ String pc = matcher.group(1);
+ pcVal = Long.parseUnsignedLong(pc, 16);
+ }
+ matcher = HEX_PATTERN.matcher(offsetRaw);
+ long offsetVal = 0;
+ boolean offsetMatched = matcher.matches();
+ if (offsetMatched) {
+ String offset = matcher.group(1);
+ offsetVal = Long.parseUnsignedLong(offset, 16);
+ }
+ if (offsetMatched && pcMatched
+ && (pcVal + offsetVal) % ADDRESS_ALIGNMENT_X86 == 0) {
+ return true;
+ }
+ return false;
+ }
+
+ private static List<String> findFibLines(List<String> lines) {
+ boolean startReached = false;
+ boolean endReached = false;
+ List<String> interestingLines = new ArrayList<>();
+ for (String line : lines) {
+ if (line.contains(LingeredAppWithNativeMethod.THREAD_NAME)) {
+ startReached = true;
+ }
+ if (startReached && line.contains("-------")) {
+ endReached = true;
+ }
+ if (startReached && !endReached) {
+ Matcher matcher = LINE_PATTERN.matcher(line);
+ if (matcher.matches()) {
+ interestingLines.add(line);
+ }
+ }
+ }
+ return interestingLines;
+ }
+
+ private static void runJstackMixedInLoop(LingeredApp app) throws Exception {
+ for (int i = 0; i < MAX_ITERATIONS; i++) {
+ JDKToolLauncher launcher = JDKToolLauncher
+ .createUsingTestJDK("jhsdb");
+ launcher.addToolArg("jstack");
+ launcher.addToolArg("--mixed");
+ launcher.addToolArg("--pid");
+ launcher.addToolArg(Long.toString(app.getPid()));
+
+ ProcessBuilder pb = new ProcessBuilder();
+ pb.command(launcher.getCommand());
+ Process jhsdb = pb.start();
+ OutputAnalyzer out = new OutputAnalyzer(jhsdb);
+
+ jhsdb.waitFor();
+
+ System.out.println(out.getStdout());
+ System.err.println(out.getStderr());
+
+ out.shouldContain(LingeredAppWithNativeMethod.THREAD_NAME);
+ if (isFibAndAlignedAddress(out.asLines())) {
+ System.out.println("DEBUG: Test triggered interesting condition.");
+ out.shouldNotContain("sun.jvm.hotspot.debugger.UnmappedAddressException:");
+ System.out.println("DEBUG: Test PASSED.");
+ return; // If we've reached here, all is well.
+ }
+ System.out.println("DEBUG: Iteration: " + (i + 1)
+ + " - Test didn't trigger interesting condition.");
+ out.shouldNotContain("sun.jvm.hotspot.debugger.UnmappedAddressException:");
+ }
+ System.out.println("DEBUG: Test didn't trigger interesting condition " +
+ "but no UnmappedAddressException was thrown. PASS!");
+ }
+
+ public static void main(String... args) throws Exception {
+
+ LingeredApp app = null;
+
+ try {
+ List<String> vmArgs = new ArrayList<String>(Utils.getVmOptions());
+ // Needed for LingeredApp to be able to resolve native library.
+ String libPath = System.getProperty("java.library.path");
+ if (libPath != null) {
+ vmArgs.add("-Djava.library.path=" + libPath);
+ }
+
+ app = new LingeredAppWithNativeMethod();
+ LingeredApp.startApp(vmArgs, app);
+ System.out.println("Started LingeredApp with pid " + app.getPid());
+ runJstackMixedInLoop(app);
+ System.out.println("Test Completed");
+ } catch (Throwable e) {
+ e.printStackTrace();
+ throw e;
+ } finally {
+ LingeredApp.stopApp(app);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/serviceability/sa/libNoFramePointer.c Mon Aug 27 16:02:55 2018 -0400
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#include <jni.h>
+
+static jlong fib(jint num) {
+ if (num == 0) {
+ return 0;
+ }
+ if (num <= 2) {
+ return 1;
+ }
+ return fib(num - 2) + fib(num -1);
+}
+
+static void callCallback(JNIEnv *env, jclass cls, jobject target, jlong result) {
+ jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "(J)V");
+ if (mid == NULL) {
+ jclass nsme = (jclass) (*env)->NewGlobalRef(env, (*env)->FindClass(env, "java/lang/NoSuchMethodException"));
+ if (nsme != NULL) {
+ (*env)->ThrowNew(env, nsme, "Can't find method callback()");
+ }
+ return;
+ }
+ (*env)->CallVoidMethod(env, target, mid, result);
+}
+
+static void calculateAndCallCallback(JNIEnv *env, jclass cls, jobject target, jint num) {
+ jlong result = -1;
+ result = fib(num);
+ callCallback(env, cls, target, result);
+}
+
+JNIEXPORT void JNICALL
+Java_LingeredAppWithNativeMethod_callJNI(JNIEnv *env, jclass cls, jobject target, jint num) {
+ calculateAndCallCallback(env, cls, target, num);
+}
--- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ThreadStart/threadstart003/threadstart003.c Mon Aug 27 16:01:38 2018 -0400
+++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ThreadStart/threadstart003/threadstart003.c Mon Aug 27 16:02:55 2018 -0400
@@ -216,7 +216,7 @@
TranslateError(err), err);
result = STATUS_FAILED;
}
- err = (*jvmti)->RawMonitorWait(jvmti, wait_lock, (jlong)WAIT_TIME);
+ err = (*jvmti)->RawMonitorWait(jvmti, wait_lock, 0);
if (err != JVMTI_ERROR_NONE) {
printf("(RawMonitorWait) unexpected error: %s (%d)\n",
TranslateError(err), err);
@@ -235,7 +235,16 @@
TranslateError(err), err);
result = STATUS_FAILED;
}
- err = (*jvmti)->RawMonitorWait(jvmti, wait_lock, (jlong)WAIT_TIME);
+ // Wait for up to 3 seconds for the thread end event
+ {
+ int i;
+ for (i = 0; i < 3 ; i++) {
+ err = (*jvmti)->RawMonitorWait(jvmti, wait_lock, (jlong)WAIT_TIME);
+ if (endsCount == endsExpected || err != JVMTI_ERROR_NONE) {
+ break;
+ }
+ }
+ }
if (err != JVMTI_ERROR_NONE) {
printf("(RawMonitorWait) unexpected error: %s (%d)\n",
TranslateError(err), err);
--- a/test/jdk/sanity/client/lib/jemmy/src/org/netbeans/jemmy/operators/ComponentOperator.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/jdk/sanity/client/lib/jemmy/src/org/netbeans/jemmy/operators/ComponentOperator.java Mon Aug 27 16:02:55 2018 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -59,8 +59,6 @@
import java.util.Hashtable;
import java.util.Locale;
-import static java.lang.Math.abs;
-
import org.netbeans.jemmy.CharBindingMap;
import org.netbeans.jemmy.ComponentChooser;
import org.netbeans.jemmy.ComponentSearcher;
@@ -1222,6 +1220,48 @@
}
/**
+ * Wait till the component reaches exact location on screen.
+ *
+ * @param exactLocation exact expected screen location.
+ */
+ public void waitComponentLocationOnScreen(Point exactlocation) {
+ waitComponentLocationOnScreen(exactlocation, exactlocation);
+ }
+
+ /**
+ * Wait till the component location on screen reaches between minLocation
+ * and maxLocation
+ *
+ * @param minLocation minimum expected location on screen.
+ * @param maxLocation maximum expected location on screen.
+ */
+ public void waitComponentLocationOnScreen(
+ final Point minLocation, final Point maxLocation) {
+ waitState(new ComponentChooser() {
+ @Override
+ public boolean checkComponent(Component comp) {
+ Point location = comp.getLocationOnScreen();
+ return location.x >= minLocation.x
+ && location.x <= maxLocation.x
+ && location.y >= minLocation.y
+ && location.y <= maxLocation.y;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Component location on screen reaches between :"
+ + minLocation + "and " + maxLocation;
+ }
+
+ @Override
+ public String toString() {
+ return "ComponentOperator.waitComponentLocationOnScreen"
+ + ".Waitable{description = " + getDescription() + '}';
+ }
+ });
+ }
+
+ /**
* Returns information about component.
*/
@Override
--- a/test/jdk/sanity/client/lib/jemmy/src/org/netbeans/jemmy/operators/JComponentOperator.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/jdk/sanity/client/lib/jemmy/src/org/netbeans/jemmy/operators/JComponentOperator.java Mon Aug 27 16:02:55 2018 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -47,7 +47,6 @@
import org.netbeans.jemmy.ComponentChooser;
import org.netbeans.jemmy.ComponentSearcher;
-import org.netbeans.jemmy.JemmyProperties;
import org.netbeans.jemmy.Outputable;
import org.netbeans.jemmy.TestOut;
import org.netbeans.jemmy.TimeoutExpiredException;
@@ -307,15 +306,7 @@
}
public JToolTip waitToolTip() {
- return ((JToolTip) waitComponent(WindowOperator.
- waitWindow(new JToolTipWindowFinder(),
- 0,
- getTimeouts(),
- getOutput()),
- new JToolTipFinder(),
- 0,
- getTimeouts(),
- getOutput()));
+ return JToolTipOperator.waitJToolTip(this);
}
/**
@@ -1228,61 +1219,4 @@
}
}
- static class JToolTipWindowFinder implements ComponentChooser {
-
- ComponentChooser ppFinder;
-
- public JToolTipWindowFinder() {
- ppFinder = new ComponentChooser() {
- @Override
- public boolean checkComponent(Component comp) {
- return (comp.isShowing()
- && comp.isVisible()
- && comp instanceof JToolTip);
- }
-
- @Override
- public String getDescription() {
- return "A tool tip";
- }
-
- @Override
- public String toString() {
- return "JComponentOperator.JToolTipWindowFinder.ComponentChooser{description = " + getDescription() + '}';
- }
- };
- }
-
- @Override
- public boolean checkComponent(Component comp) {
- if (comp.isShowing() && comp instanceof Window) {
- ComponentSearcher cs = new ComponentSearcher((Container) comp);
- cs.setOutput(JemmyProperties.getCurrentOutput().createErrorOutput());
- return (cs.findComponent(ppFinder)
- != null);
- }
- return false;
- }
-
- @Override
- public String getDescription() {
- return "A tool tip window";
- }
-
- @Override
- public String toString() {
- return "JToolTipWindowFinder{" + "ppFinder=" + ppFinder + '}';
- }
- }
-
- class JToolTipFinder extends Finder {
-
- public JToolTipFinder(ComponentChooser sf) {
- super(JToolTip.class, sf);
- }
-
- public JToolTipFinder() {
- super(JToolTip.class);
- }
- }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sanity/client/lib/jemmy/src/org/netbeans/jemmy/operators/JToolTipOperator.java Mon Aug 27 16:02:55 2018 -0400
@@ -0,0 +1,519 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.netbeans.jemmy.operators;
+
+import java.awt.Component;
+import java.awt.Window;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.swing.JComponent;
+import javax.swing.JToolTip;
+import javax.swing.plaf.ToolTipUI;
+
+import org.netbeans.jemmy.ComponentChooser;
+import org.netbeans.jemmy.ComponentSearcher;
+import org.netbeans.jemmy.TimeoutExpiredException;
+import org.netbeans.jemmy.Waitable;
+
+/**
+ * <BR>
+ * <BR>
+ * Timeouts used: <BR>
+ * {@code ComponentOperator.WaitComponentTimeout} - time to wait component
+ * displayed.<BR>
+ * {@code ComponentOperator.WaitStateTimeout} - time to wait for tip text. <BR>
+ *
+ * @see org.netbeans.jemmy.Timeouts
+ */
+public class JToolTipOperator extends JComponentOperator {
+
+ /**
+ * Identifier for a "tip text" property.
+ *
+ * @see #getDump()
+ */
+ public static final String TIP_TEXT_DPROP = "TipText";
+
+ /**
+ * Constructs a JToolTipOperator object, waiting for a shown
+ * JToolTip.
+ */
+ public JToolTipOperator() {
+ this(TRUE_CHOOSER);
+ }
+
+ /**
+ * Constructs a JToolTipOperator object for a given JToolTip component.
+ *
+ * @param toolTip
+ * a component
+ */
+ public JToolTipOperator(JToolTip toolTip) {
+ super(toolTip);
+ }
+
+ /**
+ * Constructs a JToolTipOperator object waiting for the JToolTip having a
+ * given tip text (compared using default string comparator).
+ *
+ * @param tipText
+ * tip text.
+ * @see #getDefaultStringComparator()
+ */
+ public JToolTipOperator(String tipText) {
+ this(waitJToolTip(new JToolTipByTipTextFinder(tipText,
+ getDefaultStringComparator())));
+ }
+
+ /**
+ * Constructs a JToolTipOperator object waiting for the JToolTip
+ * associated with the given component. Uses {@code comp}'s timeout and
+ * output for waiting. Copies environment from {@code comp}.
+ *
+ * @param comp
+ * component on which tool tip associated
+ * @see #copyEnvironment(org.netbeans.jemmy.operators.Operator)
+ */
+ public JToolTipOperator(ComponentOperator comp) {
+ this(comp, TRUE_CHOOSER);
+ }
+
+ /**
+ * Constructs a JToolTipOperator object waiting for the JToolTip
+ * conforming to the given component chooser.
+ *
+ * @param chooser
+ * a component chooser specifying searching criteria.
+ */
+ public JToolTipOperator(ComponentChooser chooser) {
+ this(null, chooser);
+ }
+
+ /**
+ * Constructs a JToolTipOperator object waiting for the JToolTip
+ * associated with the given component and conforming to the given
+ * component chooser. Uses {@code comp}'s timeout and output for waiting.
+ * Copies environment from {@code comp}.
+ *
+ * @param comp
+ * component on which tool tip associated
+ * @param chooser
+ * a component chooser specifying searching criteria.
+ * @see #copyEnvironment(org.netbeans.jemmy.operators.Operator)
+ */
+ public JToolTipOperator(ComponentOperator comp, ComponentChooser chooser) {
+ this(waitJToolTip(comp, chooser));
+ if(comp != null) {
+ copyEnvironment(comp);
+ }
+ }
+
+ /**
+ * Constructs a JToolTipOperator object waiting for the JToolTip
+ * associated with the given component and having the given tip text.
+ * Uses {@code comp}'s string comparator for tip text comparison, timeout
+ * and output for waiting. Copies environment from {@code comp}.
+ *
+ * @param comp
+ * component on which tool tip associated
+ * @param tipText
+ * tip text
+ * @see #getComparator()
+ * @see #copyEnvironment(org.netbeans.jemmy.operators.Operator)
+ */
+ public JToolTipOperator(ComponentOperator comp, String tipText) {
+ this(waitJToolTip(comp,
+ new JToolTipByTipTextFinder(tipText, comp.getComparator())));
+ copyEnvironment(comp);
+ }
+
+ /**
+ * Searches for the JToolTip associated with the given component and
+ * conforming to the given component chooser. Uses {@code comp}'s timeout
+ * and output for waiting.
+ *
+ * @param comp
+ * component on which tool tip associated
+ * @param chooser
+ * a component chooser specifying searching criteria.
+ * @return JToolTip instance or null if component was not found.
+ */
+ public static JToolTip findJToolTip(ComponentOperator comp,
+ ComponentChooser chooser) {
+ List<Window> windowList;
+ if(comp != null && comp.getWindow() != null) {
+ windowList = new ArrayList<>(
+ Arrays.asList(comp.getWindow().getOwnedWindows()));
+ windowList.add(comp.getWindow());
+ } else {
+ windowList = new ArrayList<>(
+ Arrays.asList(WindowOperator.getWindows()));
+ }
+ ComponentChooser toolTipChooser = new JToolTipFinder(chooser);
+ for (Window w : windowList) {
+ ComponentSearcher searcher = new ComponentSearcher(w);
+ Component[] components = searcher.findComponents(toolTipChooser);
+ if (components.length > 0) {
+ if(comp!= null && comp.getSource() != null) {
+ if(comp.getSource().equals(
+ ((JToolTip) components[0]).getComponent())) {
+ return (JToolTip) components[0];
+ }
+ } else {
+ return (JToolTip) components[0];
+ }
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Searches for a JToolTip.
+ *
+ * @return JToolTip instance or null if component was not found.
+ */
+ public static JToolTip findJToolTip() {
+ return findJToolTip(null);
+ }
+
+ /**
+ * Searches for the JToolTip associated with the given component. Uses
+ * {@code comp}'s timeout and output for waiting.
+ *
+ * @param comp
+ * component on which tool tip associated
+ * @return JToolTip instance or null if component was not found.
+ */
+ public static JToolTip findJToolTip(ComponentOperator comp) {
+ return findJToolTip(comp, TRUE_CHOOSER);
+ }
+
+ /**
+ * Searches for the JToolTip associated with the given component and
+ * looking for given tip text using specified string comparator options.
+ * Uses {@code comp}'s timeout and output for waiting.
+ *
+ * @param comp
+ * component on which tool tip associated
+ * @param tipText
+ * Tip text.
+ * @param ce
+ * Compare text exactly.
+ * @param ccs
+ * Compare text case sensitively.
+ * @return JToolTip instance or null if component was not found.
+ * @see DefaultStringComparator
+ * @see JToolTipByTipTextFinder
+ */
+ public static JToolTip findJToolTip(ComponentOperator comp, String tipText,
+ boolean ce, boolean ccs) {
+ return findJToolTip(comp, new JToolTipByTipTextFinder(tipText,
+ new DefaultStringComparator(ce, ccs)));
+ }
+
+ /**
+ * Waits for a JToolTip.
+ *
+ * @return JToolTip instance.
+ * @see TimeoutExpiredException
+ */
+ public static JToolTip waitJToolTip() {
+ return waitJToolTip(TRUE_CHOOSER);
+ }
+
+
+ /**
+ * Waits for the first JToolTip associated with the given component.
+ *
+ * @param comp
+ * component on which tool tip associated
+ * @return JToolTip instance.
+ * @see TimeoutExpiredException
+ */
+ public static JToolTip waitJToolTip(ComponentOperator comp) {
+ return waitJToolTip(comp, TRUE_CHOOSER);
+ }
+
+ /**
+ * Waits for the JToolTip conforming to the given component
+ * chooser.
+ *
+ * @param chooser
+ * a component chooser specifying searching criteria.
+ * @return JToolTip instance.
+ * @see TimeoutExpiredException
+ */
+ public static JToolTip waitJToolTip(ComponentChooser chooser) {
+ return waitJToolTip(null, chooser);
+ }
+
+ /**
+ * Waits for the JToolTip associated with the given component and
+ * conforming to the specified component chooser.
+ *
+ * @param comp
+ * component on which tool tip associated
+ * @param chooser
+ * a component chooser specifying searching criteria.
+ * @return JToolTip instance.
+ * @see TimeoutExpiredException
+ */
+ public static JToolTip waitJToolTip(ComponentOperator comp,
+ ComponentChooser chooser) {
+ return Operator.getEnvironmentOperator().
+ waitState(new Waitable<JToolTip, Void>() {
+ @Override
+ public JToolTip actionProduced(Void obj) {
+ return findJToolTip(comp, chooser);
+ }
+
+ @Override
+ public String getDescription() {
+ return "Wait for JTooltip to be displayed for Component = "
+ + comp + ", " + "chooser = " + chooser;
+ }
+
+ @Override
+ public String toString() {
+ return "JToolTipOperator.waitJToolTip.Waitable{description = "
+ + getDescription() + '}';
+ }
+ });
+ }
+
+ /**
+ * Waits for the JToolTip associated with the given component and having
+ * the given tip text compared using given string comparator options.
+ *
+ * @param comp
+ * component on which tool tip associated
+ * @param tipText
+ * Tip text.
+ * @param ce
+ * Compare text exactly.
+ * @param ccs
+ * Compare text case sensitively.
+ * @return JToolTip instance.
+ * @see TimeoutExpiredException
+ */
+ public static JToolTip waitJToolTip(ComponentOperator comp, String tipText,
+ boolean ce, boolean ccs) {
+ return waitJToolTip(comp, new JToolTipByTipTextFinder(tipText,
+ new DefaultStringComparator(ce, ccs)));
+ }
+
+ /**
+ * Waits for the given tip text. Uses {@linkplain #getComparator()}
+ * comparator.
+ *
+ * @param tipText
+ * Tip text to wait for.
+ * @see TimeoutExpiredException
+ */
+ public void waitTipText(String tipText) {
+ getOutput().printLine("Wait \"" + tipText
+ + "\" tip text in JToolTip \n : " + toStringSource());
+ getOutput().printGolden("Wait \"" + tipText + "\" tip text");
+ waitState(new JToolTipByTipTextFinder(tipText, getComparator()));
+ }
+
+ /**
+ * Returns information about the component.
+ *
+ * @return Map of component properties.
+ */
+ @Override
+ public Hashtable<String, Object> getDump() {
+ Hashtable<String, Object> result = super.getDump();
+ String tipText = getTipText();
+ if (tipText != null) {
+ result.put(TIP_TEXT_DPROP, tipText);
+ } else {
+ result.put(TIP_TEXT_DPROP, "null");
+ }
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////
+ // Mapping //
+
+ /**
+ * Maps {@linkplain JToolTip#getTipText()} through queue
+ *
+ * @return
+ */
+ public String getTipText() {
+ return runMapping(new MapAction<String>("getTipText") {
+ @Override
+ public String map() {
+ return ((JToolTip) getSource()).getTipText();
+ }
+ });
+ }
+
+ /**
+ * Maps {@linkplain JToolTip#getComponent()} through queue
+ *
+ * @return
+ */
+ public JComponent getComponent() {
+ return runMapping(new MapAction<JComponent>("getComponent") {
+ @Override
+ public JComponent map() {
+ return ((JToolTip) getSource()).getComponent();
+ }
+ });
+ }
+
+ /**
+ * Maps {@linkplain JToolTip#getUI()} through queue
+ *
+ * @return
+ */
+ public ToolTipUI getUI() {
+ return runMapping(new MapAction<ToolTipUI>("getUI") {
+ @Override
+ public ToolTipUI map() {
+ return ((JToolTip) getSource()).getUI();
+ }
+ });
+ }
+
+ /**
+ * Maps {@linkplain JToolTip#setTipText(String)} through queue
+ *
+ * @param tipText
+ */
+ public void setTipText(final String tipText) {
+ runMapping(new MapVoidAction("setTipText") {
+ @Override
+ public void map() {
+ ((JToolTip) getSource()).setTipText(tipText);
+ }
+ });
+ }
+
+ /**
+ * Maps {@linkplain JToolTip#setComponent(JComponent)} through queue
+ *
+ * @param component
+ */
+ public void setComponent(final JComponent component) {
+ runMapping(new MapVoidAction("setComponent") {
+ @Override
+ public void map() {
+ ((JToolTip) getSource()).setComponent(component);
+ }
+ });
+ }
+ // End of mapping //
+ ////////////////////////////////////////////////////////
+
+
+ /**
+ * Allows to find JToolTip by tip text.
+ */
+ public static class JToolTipByTipTextFinder implements ComponentChooser {
+
+ String tipText;
+ StringComparator comparator;
+
+ /**
+ * Constructs JToolTipByTipTextFinder.
+ *
+ * @param tipText
+ * a tip text pattern
+ * @param comparator
+ * specifies string comparison algorithm.
+ */
+ public JToolTipByTipTextFinder(String tipText,
+ StringComparator comparator) {
+ this.tipText = tipText;
+ this.comparator = comparator;
+ }
+
+ /**
+ * Constructs JToolTipByTipTextFinder.
+ *
+ * @param tipText
+ * a tip text pattern
+ */
+ public JToolTipByTipTextFinder(String tipText) {
+ this(tipText, Operator.getDefaultStringComparator());
+ }
+
+ @Override
+ public boolean checkComponent(Component comp) {
+ if (comp instanceof JToolTip) {
+ if (((JToolTip) comp).getTipText() != null) {
+ return (comparator.equals(((JToolTip) comp).getTipText(),
+ tipText));
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String getDescription() {
+ return "JToolTip with tip text \"" + tipText + "\"";
+ }
+
+ @Override
+ public String toString() {
+ return "JToolTipByTipTextFinder{" + "tipText=" + tipText
+ + ", comparator=" + comparator + '}';
+ }
+ }
+
+ /**
+ * Allows to find JToolTips among components.
+ */
+ public static class JToolTipFinder extends Finder {
+
+ /**
+ * Constructs JToolTipFinder chaining another component chooser.
+ *
+ * @param sf
+ * other searching criteria.
+ */
+ public JToolTipFinder(ComponentChooser sf) {
+ super(JToolTip.class, sf);
+ }
+
+ /**
+ * Constructs JToolTipFinder.
+ */
+ public JToolTipFinder() {
+ super(JToolTip.class);
+ }
+ }
+
+ private static final ComponentChooser TRUE_CHOOSER = ComponentSearcher
+ .getTrueChooser("Any JToolTip");
+}
--- a/test/jdk/sanity/client/lib/jemmy/src/org/netbeans/jemmy/operators/Operator.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/jdk/sanity/client/lib/jemmy/src/org/netbeans/jemmy/operators/Operator.java Mon Aug 27 16:02:55 2018 -0400
@@ -693,7 +693,7 @@
* defined by {@code "ComponentOperator.WaitStateTimeout"}
*/
public void waitState(final ComponentChooser state) {
- Waiter<String, Void> stateWaiter = new Waiter<>(new Waitable<String, Void>() {
+ waitState(new Waitable<String, Void>() {
@Override
public String actionProduced(Void obj) {
return state.checkComponent(getSource()) ? "" : null;
@@ -710,13 +710,20 @@
return "Operator.waitState.Waitable{description = " + getDescription() + '}';
}
});
- stateWaiter.setTimeoutsToCloneOf(getTimeouts(), "ComponentOperator.WaitStateTimeout");
+ }
+
+ public <R> R waitState(Waitable<R, Void> waitable) {
+ Waiter<R, Void> stateWaiter = new Waiter<>(waitable);
+ stateWaiter.setTimeoutsToCloneOf(getTimeouts(),
+ "ComponentOperator.WaitStateTimeout");
stateWaiter.setOutput(getOutput().createErrorOutput());
try {
- stateWaiter.waitAction(null);
+ return stateWaiter.waitAction(null);
} catch (InterruptedException e) {
- throw (new JemmyException("Waiting of \"" + state.getDescription()
- + "\" state has been interrupted!"));
+ Thread.currentThread().interrupt();
+ throw (new JemmyException(
+ "Waiting of \"" + waitable.getDescription()
+ + "\" state has been interrupted!"));
}
}
--- a/test/jdk/sanity/client/lib/jemmy/src/org/netbeans/jemmy/operators/WindowOperator.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/jdk/sanity/client/lib/jemmy/src/org/netbeans/jemmy/operators/WindowOperator.java Mon Aug 27 16:02:55 2018 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -36,6 +36,7 @@
import org.netbeans.jemmy.JemmyException;
import org.netbeans.jemmy.JemmyProperties;
import org.netbeans.jemmy.Outputable;
+import org.netbeans.jemmy.QueueTool;
import org.netbeans.jemmy.TestOut;
import org.netbeans.jemmy.TimeoutExpiredException;
import org.netbeans.jemmy.Timeouts;
@@ -585,6 +586,21 @@
});
}
+ /**
+ * Maps {@code Window.getWindows()} through queue
+ *
+ * @return result of {@code Window.getWindows()}
+ */
+ public static Window[] getWindows() {
+ return new QueueTool().invokeSmoothly(
+ new QueueTool.QueueAction<Window[]>("getWindows") {
+ @Override
+ public Window[] launch() throws Exception {
+ return Window.getWindows();
+ }
+ });
+ }
+
//End of mapping //
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
--- a/test/jdk/sanity/client/lib/jemmy/src/org/netbeans/jemmy/version_info Mon Aug 27 16:01:38 2018 -0400
+++ b/test/jdk/sanity/client/lib/jemmy/src/org/netbeans/jemmy/version_info Mon Aug 27 16:02:55 2018 -0400
@@ -1,6 +1,6 @@
Manifest-version: 1.0
Main-Class: org.netbeans.jemmy.JemmyProperties
Jemmy-MajorVersion: 3.0
-Jemmy-MinorVersion: 3.0
+Jemmy-MinorVersion: 4.0
Jemmy-Build: @BUILD_NUMBER@
--- a/test/jdk/sun/security/smartcardio/TestTransmit.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/jdk/sun/security/smartcardio/TestTransmit.java Mon Aug 27 16:02:55 2018 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6293769 6294527
+ * @bug 6293769 6294527 6474858
* @summary test transmit() works
* @author Andreas Sterbenz
* @modules java.smartcardio/javax.smartcardio
@@ -90,6 +90,13 @@
} // else ignore
}
+ // JDK-6474858 : CardChannel.transmit(CommandAPDU) throws
+ // unexpected ArrayIndexOutOfBoundsException
+ {
+ CommandAPDU capdu2 = new CommandAPDU(0x00, 0xA4, 0x00, 0x00);
+ channel.transmit(capdu2);
+ }
+
// disconnect
card.disconnect(true);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/T8209173/CodeCompletionExceptTest.java Mon Aug 27 16:02:55 2018 -0400
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8209173
+ * @summary javac fails with completion exception while reporting an error
+ * @library /tools/lib
+ * @modules jdk.jdeps/com.sun.tools.classfile
+ * jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.compiler/com.sun.tools.javac.util
+ * jdk.jdeps/com.sun.tools.javap
+ * @build toolbox.ToolBox toolbox.JavacTask
+ * @run main CodeCompletionExceptTest
+ */
+
+import java.io.File;
+
+import toolbox.JavacTask;
+import toolbox.Task;
+import toolbox.ToolBox;
+
+public class CodeCompletionExceptTest {
+ private static final String MyListSource =
+ "import java.util.List;\n" +
+ "public interface MyList<E> extends List<E> {}";
+
+ private static final String C1Source =
+ "public class C1 {\n" +
+ " int m(MyList<Integer> list) {\n" +
+ " return 0;\n" +
+ " }\n" +
+ "}";
+
+ private static final String C2Source =
+ "class C2 {\n" +
+ " void m() {\n" +
+ " (new C1()).m(1, 2, 3);\n" +
+ " }\n" +
+ "}";
+
+ public static void main(String[] args) throws Exception {
+ new CodeCompletionExceptTest().run();
+ }
+
+ ToolBox tb = new ToolBox();
+
+ void run() throws Exception {
+ // first we compile MyList
+ new JavacTask(tb)
+ .sources(MyListSource)
+ .run();
+
+ // then with MyList.class in the cp we compile C1
+ new JavacTask(tb)
+ .sources(C1Source)
+ .classpath(System.getProperty("user.dir"))
+ .run();
+ // now we delete MyList.class
+ tb.deleteFiles(System.getProperty("user.dir") + File.separatorChar + "MyList.class");
+ /** and try to compile C2 which uses C1 which uses MyList but, MyList won't be in the
+ * classpath so its symbol can't be completed while javac is generating the diagnostic error
+ * the compiler should capture the completion exception and still be able to produce an error
+ * message without crashing
+ */
+ String javacOut = new JavacTask(tb)
+ .sources(C2Source)
+ .classpath(System.getProperty("user.dir"))
+ .options("-XDrawDiagnostics")
+ .run(Task.Expect.FAIL)
+ .writeAll()
+ .getOutput(Task.OutputKind.DIRECT);
+ String expectedOuput =
+ "C2.java:3:19: compiler.err.cant.apply.symbol: kindname.method, m, MyList<java.lang.Integer>, int,int,int, kindname.class, C1, (compiler.misc.arg.length.mismatch)";
+ if (!javacOut.contains(expectedOuput)) {
+ throw new Exception("test failed, unexpected output");
+ }
+ }
+}
--- a/test/lib/jdk/test/lib/cds/CDSTestUtils.java Mon Aug 27 16:01:38 2018 -0400
+++ b/test/lib/jdk/test/lib/cds/CDSTestUtils.java Mon Aug 27 16:02:55 2018 -0400
@@ -200,11 +200,19 @@
}
}
- // Specify this property to copy sdandard output of the child test process to
- // the parent/main stdout of the test.
- // By default such output is logged into a file, and is copied into the main stdout.
- public static final boolean CopyChildStdoutToMainStdout =
- Boolean.valueOf(System.getProperty("test.cds.copy.child.stdout", "true"));
+ // A number to be included in the filename of the stdout and the stderr output file.
+ static int logCounter = 0;
+
+ private static int getNextLogCounter() {
+ return logCounter++;
+ }
+
+ // By default, stdout of child processes are logged in files such as
+ // <testname>-0000-exec.stdout. If you want to also include the stdout
+ // inside jtr files, you can override this in the jtreg command line like
+ // "jtreg -Dtest.cds.copy.child.stdout=true ...."
+ public static final boolean copyChildStdoutToMainStdout =
+ Boolean.getBoolean("test.cds.copy.child.stdout");
// This property is passed to child test processes
public static final String TestTimeoutFactor = System.getProperty("test.timeout.factor", "1.0");
@@ -549,13 +557,17 @@
public static OutputAnalyzer executeAndLog(ProcessBuilder pb, String logName) throws Exception {
long started = System.currentTimeMillis();
OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ String outputFileNamePrefix =
+ getTestName() + "-" + String.format("%04d", getNextLogCounter()) + "-" + logName;
- writeFile(getOutputFile(logName + ".stdout"), output.getStdout());
- writeFile(getOutputFile(logName + ".stderr"), output.getStderr());
+ writeFile(getOutputFile(outputFileNamePrefix + ".stdout"), output.getStdout());
+ writeFile(getOutputFile(outputFileNamePrefix + ".stderr"), output.getStderr());
System.out.println("[ELAPSED: " + (System.currentTimeMillis() - started) + " ms]");
+ System.out.println("[logging stdout to " + outputFileNamePrefix + ".stdout]");
+ System.out.println("[logging stderr to " + outputFileNamePrefix + ".stderr]");
System.out.println("[STDERR]\n" + output.getStderr());
- if (CopyChildStdoutToMainStdout)
+ if (copyChildStdoutToMainStdout)
System.out.println("[STDOUT]\n" + output.getStdout());
return output;