--- a/.hgtags-top-repo Thu Sep 04 13:26:26 2014 -0700
+++ b/.hgtags-top-repo Wed Jul 05 19:59:54 2017 +0200
@@ -271,3 +271,4 @@
d3ec8d048e6c3c46b6e0ee011cc551ad386dfba5 jdk9-b26
ba5645f2735b41ed085d07ba20fa7b322afff318 jdk9-b27
ea2f7981236f3812436958748ab3d26e80a35130 jdk9-b28
+9e6581aeda388a23fbee021fc33e6aa152a60657 jdk9-b29
--- a/corba/.hgtags Thu Sep 04 13:26:26 2014 -0700
+++ b/corba/.hgtags Wed Jul 05 19:59:54 2017 +0200
@@ -271,3 +271,4 @@
6c777df597bbf5abba3488d44c401edfe73c74af jdk9-b26
7e06bf1dcb0907b80ddf59315426ce9ce775e56d jdk9-b27
a00b04ef067e39f50b9a0fea6f1904e35d632a73 jdk9-b28
+163a9cd806fd09970baf1f5f42b92a3cfe7ee945 jdk9-b29
--- a/hotspot/.hgtags Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/.hgtags Wed Jul 05 19:59:54 2017 +0200
@@ -431,3 +431,4 @@
48b95a073d752d6891cc0d1d2836b321ecf3ce0c jdk9-b26
f95347244306affc32ce3056f27ceff7b2100810 jdk9-b27
657294869d7ff063e055f5492cab7ce5612ca851 jdk9-b28
+deb29e92f68ace2808a36ecfa18c7d61dcb645bb jdk9-b29
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java Wed Jul 05 19:59:54 2017 +0200
@@ -43,8 +43,8 @@
// Mirror class for G1CollectedHeap.
public class G1CollectedHeap extends SharedHeap {
- // HeapRegionSeq _seq;
- static private long hrsFieldOffset;
+ // HeapRegionManager _hrm;
+ static private long hrmFieldOffset;
// MemRegion _g1_reserved;
static private long g1ReservedFieldOffset;
// size_t _summary_bytes_used;
@@ -67,7 +67,7 @@
static private synchronized void initialize(TypeDataBase db) {
Type type = db.lookupType("G1CollectedHeap");
- hrsFieldOffset = type.getField("_hrs").getOffset();
+ hrmFieldOffset = type.getField("_hrm").getOffset();
summaryBytesUsedField = type.getCIntegerField("_summary_bytes_used");
g1mmField = type.getAddressField("_g1mm");
oldSetFieldOffset = type.getField("_old_set").getOffset();
@@ -75,7 +75,7 @@
}
public long capacity() {
- return hrs().capacity();
+ return hrm().capacity();
}
public long used() {
@@ -83,13 +83,13 @@
}
public long n_regions() {
- return hrs().length();
+ return hrm().length();
}
- private HeapRegionSeq hrs() {
- Address hrsAddr = addr.addOffsetTo(hrsFieldOffset);
- return (HeapRegionSeq) VMObjectFactory.newObject(HeapRegionSeq.class,
- hrsAddr);
+ private HeapRegionManager hrm() {
+ Address hrmAddr = addr.addOffsetTo(hrmFieldOffset);
+ return (HeapRegionManager) VMObjectFactory.newObject(HeapRegionManager.class,
+ hrmAddr);
}
public G1MonitoringSupport g1mm() {
@@ -110,7 +110,7 @@
}
private Iterator<HeapRegion> heapRegionIterator() {
- return hrs().heapRegionIterator();
+ return hrm().heapRegionIterator();
}
public void heapRegionIterate(SpaceClosure scl) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionManager.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2011, 2014, 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 sun.jvm.hotspot.gc_implementation.g1;
+
+import java.util.Iterator;
+import java.util.Observable;
+import java.util.Observer;
+
+import sun.jvm.hotspot.debugger.Address;
+import sun.jvm.hotspot.runtime.VM;
+import sun.jvm.hotspot.runtime.VMObject;
+import sun.jvm.hotspot.runtime.VMObjectFactory;
+import sun.jvm.hotspot.types.AddressField;
+import sun.jvm.hotspot.types.CIntegerField;
+import sun.jvm.hotspot.types.Type;
+import sun.jvm.hotspot.types.TypeDataBase;
+
+// Mirror class for HeapRegionManager.
+
+public class HeapRegionManager extends VMObject {
+ // G1HeapRegionTable _regions
+ static private long regionsFieldOffset;
+ // uint _committed_length
+ static private CIntegerField numCommittedField;
+
+ static {
+ VM.registerVMInitializedObserver(new Observer() {
+ public void update(Observable o, Object data) {
+ initialize(VM.getVM().getTypeDataBase());
+ }
+ });
+ }
+
+ static private synchronized void initialize(TypeDataBase db) {
+ Type type = db.lookupType("HeapRegionManager");
+
+ regionsFieldOffset = type.getField("_regions").getOffset();
+ numCommittedField = type.getCIntegerField("_num_committed");
+ }
+
+ private G1HeapRegionTable regions() {
+ Address regionsAddr = addr.addOffsetTo(regionsFieldOffset);
+ return (G1HeapRegionTable) VMObjectFactory.newObject(G1HeapRegionTable.class,
+ regionsAddr);
+ }
+
+ public long capacity() {
+ return length() * HeapRegion.grainBytes();
+ }
+
+ public long length() {
+ return regions().length();
+ }
+
+ public long committedLength() {
+ return numCommittedField.getValue(addr);
+ }
+
+ public Iterator<HeapRegion> heapRegionIterator() {
+ return regions().heapRegionIterator(length());
+ }
+
+ public HeapRegionManager(Address addr) {
+ super(addr);
+ }
+}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSeq.java Thu Sep 04 13:26:26 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2011, 2013, 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 sun.jvm.hotspot.gc_implementation.g1;
-
-import java.util.Iterator;
-import java.util.Observable;
-import java.util.Observer;
-
-import sun.jvm.hotspot.debugger.Address;
-import sun.jvm.hotspot.runtime.VM;
-import sun.jvm.hotspot.runtime.VMObject;
-import sun.jvm.hotspot.runtime.VMObjectFactory;
-import sun.jvm.hotspot.types.AddressField;
-import sun.jvm.hotspot.types.CIntegerField;
-import sun.jvm.hotspot.types.Type;
-import sun.jvm.hotspot.types.TypeDataBase;
-
-// Mirror class for HeapRegionSeq. It essentially encapsulates the G1HeapRegionTable.
-
-public class HeapRegionSeq extends VMObject {
- // G1HeapRegionTable _regions
- static private long regionsFieldOffset;
- // uint _committed_length
- static private CIntegerField numCommittedField;
-
- static {
- VM.registerVMInitializedObserver(new Observer() {
- public void update(Observable o, Object data) {
- initialize(VM.getVM().getTypeDataBase());
- }
- });
- }
-
- static private synchronized void initialize(TypeDataBase db) {
- Type type = db.lookupType("HeapRegionSeq");
-
- regionsFieldOffset = type.getField("_regions").getOffset();
- numCommittedField = type.getCIntegerField("_num_committed");
- }
-
- private G1HeapRegionTable regions() {
- Address regionsAddr = addr.addOffsetTo(regionsFieldOffset);
- return (G1HeapRegionTable) VMObjectFactory.newObject(G1HeapRegionTable.class,
- regionsAddr);
- }
-
- public long capacity() {
- return length() * HeapRegion.grainBytes();
- }
-
- public long length() {
- return regions().length();
- }
-
- public long committedLength() {
- return numCommittedField.getValue(addr);
- }
-
- public Iterator<HeapRegion> heapRegionIterator() {
- return regions().heapRegionIterator(length());
- }
-
- public HeapRegionSeq(Address addr) {
- super(addr);
- }
-}
--- a/hotspot/make/Makefile Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/make/Makefile Wed Jul 05 19:59:54 2017 +0200
@@ -721,6 +721,19 @@
($(CD) $(JDK_IMAGE_DIR)/debug && $(TAR) -xf -) ; \
fi
+copy_optimized_jdk::
+ $(RM) -r $(JDK_IMAGE_DIR)/optimized
+ $(MKDIR) -p $(JDK_IMAGE_DIR)/optimized
+ if [ -d $(JDK_IMPORT_PATH)/optimized ] ; then \
+ ($(CD) $(JDK_IMPORT_PATH)/optimized && \
+ $(TAR) -cf - $(JDK_DIRS)) | \
+ ($(CD) $(JDK_IMAGE_DIR)/optimized && $(TAR) -xf -) ; \
+ else \
+ ($(CD) $(JDK_IMPORT_PATH) && \
+ $(TAR) -cf - $(JDK_DIRS)) | \
+ ($(CD) $(JDK_IMAGE_DIR)/optimized && $(TAR) -xf -) ; \
+ fi
+
#
# Check target
#
--- a/hotspot/make/jprt.gmk Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/make/jprt.gmk Wed Jul 05 19:59:54 2017 +0200
@@ -42,6 +42,9 @@
jprt_build_fastdebugEmb:
$(MAKE) JAVASE_EMBEDDED=true MINIMIZE_RAM_USAGE=true jprt_build_fastdebug
+jprt_build_optimizedEmb:
+ $(MAKE) JAVASE_EMBEDDED=true MINIMIZE_RAM_USAGE=true jprt_build_optimized
+
jprt_build_productOpen:
$(MAKE) OPENJDK=true jprt_build_product
@@ -51,6 +54,9 @@
jprt_build_fastdebugOpen:
$(MAKE) OPENJDK=true jprt_build_fastdebug
+jprt_build_optimizedOpen:
+ $(MAKE) OPENJDK=true jprt_build_optimized
+
jprt_build_product: all_product copy_product_jdk export_product_jdk
( $(CD) $(JDK_IMAGE_DIR) && \
$(ZIPEXE) $(ZIPFLAGS) -r $(JPRT_ARCHIVE_BUNDLE) . )
@@ -63,5 +69,9 @@
( $(CD) $(JDK_IMAGE_DIR)/debug && \
$(ZIPEXE) $(ZIPFLAGS) -r $(JPRT_ARCHIVE_BUNDLE) . )
-.PHONY: jprt_build_product jprt_build_fastdebug jprt_build_debug
+jprt_build_optimized: all_optimized copy_optimized_jdk export_optimized_jdk
+ ( $(CD) $(JDK_IMAGE_DIR)/optimized && \
+ $(ZIPEXE) $(ZIPFLAGS) -r $(JPRT_ARCHIVE_BUNDLE) . )
+.PHONY: jprt_build_product jprt_build_fastdebug jprt_build_debug jprt_build_optimized
+
--- a/hotspot/make/jprt.properties Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/make/jprt.properties Wed Jul 05 19:59:54 2017 +0200
@@ -93,13 +93,13 @@
# Standard list of jprt build targets for this source tree
jprt.build.targets.standard= \
- ${jprt.my.solaris.sparcv9}-{product|fastdebug|optimized}, \
+ ${jprt.my.solaris.sparcv9}-{product|fastdebug}, \
${jprt.my.solaris.x64}-{product|fastdebug}, \
${jprt.my.linux.i586}-{product|fastdebug}, \
- ${jprt.my.linux.x64}-{product|fastdebug|optimized}, \
+ ${jprt.my.linux.x64}-{product|fastdebug}, \
${jprt.my.macosx.x64}-{product|fastdebug}, \
${jprt.my.windows.i586}-{product|fastdebug}, \
- ${jprt.my.windows.x64}-{product|fastdebug|optimized}, \
+ ${jprt.my.windows.x64}-{product|fastdebug}, \
${jprt.my.linux.armvh}-{product|fastdebug}
jprt.build.targets.open= \
--- a/hotspot/make/windows/makefiles/vm.make Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/make/windows/makefiles/vm.make Wed Jul 05 19:59:54 2017 +0200
@@ -34,6 +34,9 @@
CXX_FLAGS=$(CXX_FLAGS) /D "PRODUCT"
!else
CXX_FLAGS=$(CXX_FLAGS) /D "ASSERT"
+!if "$(BUILDARCH)" == "amd64"
+CXX_FLAGS=$(CXX_FLAGS) /homeparams
+!endif
!endif
!if "$(Variant)" == "compiler1"
--- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -604,6 +604,17 @@
#if INCLUDE_RTM_OPT
if (UseRTMLocking) {
+ if (is_intel_family_core()) {
+ if ((_model == CPU_MODEL_HASWELL_E3) ||
+ (_model == CPU_MODEL_HASWELL_E7 && _stepping < 3) ||
+ (_model == CPU_MODEL_BROADWELL && _stepping < 4)) {
+ if (!UnlockExperimentalVMOptions) {
+ vm_exit_during_initialization("UseRTMLocking is only available as experimental option on this platform. It must be enabled via -XX:+UnlockExperimentalVMOptions flag.");
+ } else {
+ warning("UseRTMLocking is only available as experimental option on this platform.");
+ }
+ }
+ }
if (!FLAG_IS_CMDLINE(UseRTMLocking)) {
// RTM locking should be used only for applications with
// high lock contention. For now we do not use it by default.
--- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -276,7 +276,10 @@
CPU_MODEL_WESTMERE_EX = 0x2f,
CPU_MODEL_SANDYBRIDGE = 0x2a,
CPU_MODEL_SANDYBRIDGE_EP = 0x2d,
- CPU_MODEL_IVYBRIDGE_EP = 0x3a
+ CPU_MODEL_IVYBRIDGE_EP = 0x3a,
+ CPU_MODEL_HASWELL_E3 = 0x3c,
+ CPU_MODEL_HASWELL_E7 = 0x3f,
+ CPU_MODEL_BROADWELL = 0x3d
} cpuExtendedFamily;
// cpuid information block. All info derived from executing cpuid with
--- a/hotspot/src/os/windows/vm/os_windows.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/os/windows/vm/os_windows.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -135,11 +135,6 @@
if (ForceTimeHighResolution)
timeEndPeriod(1L);
- // Workaround for issue when a custom launcher doesn't call
- // DestroyJavaVM and NMT is trying to track memory when free is
- // called from a static destructor
- MemTracker::shutdown();
-
break;
default:
break;
@@ -414,6 +409,8 @@
LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo);
+extern jint volatile vm_getting_terminated;
+
// Thread start routine for all new Java threads
static unsigned __stdcall java_start(Thread* thread) {
// Try to randomize the cache line index of hot stack frames.
@@ -435,9 +432,17 @@
}
}
+ // Diagnostic code to investigate JDK-6573254 (Part I)
+ unsigned res = 90115; // non-java thread
+ if (thread->is_Java_thread()) {
+ JavaThread* java_thread = (JavaThread*)thread;
+ res = java_lang_Thread::is_daemon(java_thread->threadObj())
+ ? 70115 // java daemon thread
+ : 80115; // java non-daemon thread
+ }
// Install a win32 structured exception handler around every thread created
- // by VM, so VM can genrate error dump when an exception occurred in non-
+ // by VM, so VM can generate error dump when an exception occurred in non-
// Java thread (e.g. VM thread).
__try {
thread->run();
@@ -453,6 +458,11 @@
Atomic::dec_ptr((intptr_t*)&os::win32::_os_thread_count);
}
+ // Diagnostic code to investigate JDK-6573254 (Part II)
+ if (OrderAccess::load_acquire(&vm_getting_terminated)) {
+ return res;
+ }
+
return 0;
}
--- a/hotspot/src/share/tools/ProjectCreator/BuildConfig.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/tools/ProjectCreator/BuildConfig.java Wed Jul 05 19:59:54 2017 +0200
@@ -504,7 +504,7 @@
super.init(includes, defines);
- getV("CompilerFlags").addAll(getCI().getDebugCompilerFlags(getOptFlag()));
+ getV("CompilerFlags").addAll(getCI().getDebugCompilerFlags(getOptFlag(), get("PlatformName")));
getV("LinkerFlags").addAll(getCI().getDebugLinkerFlags());
}
}
@@ -619,7 +619,7 @@
abstract class CompilerInterface {
abstract Vector getBaseCompilerFlags(Vector defines, Vector includes, String outDir);
abstract Vector getBaseLinkerFlags(String outDir, String outDll, String platformName);
- abstract Vector getDebugCompilerFlags(String opt);
+ abstract Vector getDebugCompilerFlags(String opt, String platformName);
abstract Vector getDebugLinkerFlags();
abstract void getAdditionalNonKernelLinkerFlags(Vector rv);
abstract Vector getProductCompilerFlags();
--- a/hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC10.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC10.java Wed Jul 05 19:59:54 2017 +0200
@@ -357,7 +357,7 @@
}
@Override
- Vector getDebugCompilerFlags(String opt) {
+ Vector getDebugCompilerFlags(String opt, String platformName) {
Vector rv = new Vector();
// Set /On option
@@ -369,6 +369,10 @@
addAttr(rv, "RuntimeLibrary", "MultiThreadedDLL");
// Set /Oy- option
addAttr(rv, "OmitFramePointers", "false");
+ // Set /homeparams for x64 debug builds
+ if(platformName.equals("x64")) {
+ addAttr(rv, "AdditionalOptions", "/homeparams");
+ }
return rv;
}
--- a/hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC7.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC7.java Wed Jul 05 19:59:54 2017 +0200
@@ -284,7 +284,7 @@
}
- Vector getDebugCompilerFlags(String opt) {
+ Vector getDebugCompilerFlags(String opt, String platformName) {
Vector rv = new Vector();
getDebugCompilerFlags_common(opt, rv);
--- a/hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC8.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC8.java Wed Jul 05 19:59:54 2017 +0200
@@ -48,7 +48,7 @@
}
- Vector getDebugCompilerFlags(String opt) {
+ Vector getDebugCompilerFlags(String opt, String platformName) {
Vector rv = new Vector();
getDebugCompilerFlags_common(opt,rv);
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -328,9 +328,11 @@
void ConcurrentMarkSweepGeneration::initialize_performance_counters() {
const char* gen_name = "old";
+ GenCollectorPolicy* gcp = (GenCollectorPolicy*) GenCollectedHeap::heap()->collector_policy();
// Generation Counters - generation 1, 1 subspace
- _gen_counters = new GenerationCounters(gen_name, 1, 1, &_virtual_space);
+ _gen_counters = new GenerationCounters(gen_name, 1, 1,
+ gcp->min_old_size(), gcp->max_old_size(), &_virtual_space);
_space_counters = new GSpaceCounters(gen_name, 0,
_virtual_space.reserved_size(),
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -34,8 +34,8 @@
#include "gc_implementation/g1/g1OopClosures.inline.hpp"
#include "gc_implementation/g1/g1RemSet.hpp"
#include "gc_implementation/g1/heapRegion.inline.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
#include "gc_implementation/g1/heapRegionRemSet.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
#include "gc_implementation/g1/heapRegionSet.inline.hpp"
#include "gc_implementation/shared/vmGCOperations.hpp"
#include "gc_implementation/shared/gcTimer.hpp"
@@ -434,10 +434,6 @@
}
}
-bool ConcurrentMark::not_yet_marked(oop obj) const {
- return _g1h->is_obj_ill(obj);
-}
-
CMRootRegions::CMRootRegions() :
_young_list(NULL), _cm(NULL), _scan_in_progress(false),
_should_abort(false), _next_survivor(NULL) { }
@@ -892,7 +888,16 @@
}
virtual bool doHeapRegion(HeapRegion* r) {
- return _bitmap->getNextMarkedWordAddress(r->bottom(), r->end()) != r->end();
+ // This closure can be called concurrently to the mutator, so we must make sure
+ // that the result of the getNextMarkedWordAddress() call is compared to the
+ // value passed to it as limit to detect any found bits.
+ // We can use the region's orig_end() for the limit and the comparison value
+ // as it always contains the "real" end of the region that never changes and
+ // has no side effects.
+ // Due to the latter, there can also be no problem with the compiler generating
+ // reloads of the orig_end() call.
+ HeapWord* end = r->orig_end();
+ return _bitmap->getNextMarkedWordAddress(r->bottom(), end) != end;
}
};
@@ -1117,20 +1122,17 @@
if (!_cm->has_aborted()) {
do {
double start_vtime_sec = os::elapsedVTime();
- double start_time_sec = os::elapsedTime();
double mark_step_duration_ms = G1ConcMarkStepDurationMillis;
the_task->do_marking_step(mark_step_duration_ms,
true /* do_termination */,
false /* is_serial*/);
- double end_time_sec = os::elapsedTime();
double end_vtime_sec = os::elapsedVTime();
double elapsed_vtime_sec = end_vtime_sec - start_vtime_sec;
- double elapsed_time_sec = end_time_sec - start_time_sec;
_cm->clear_has_overflown();
- bool ret = _cm->do_yield_check(worker_id);
+ _cm->do_yield_check(worker_id);
jlong sleep_time_ms;
if (!_cm->has_aborted() && the_task->has_aborted()) {
@@ -1140,17 +1142,6 @@
os::sleep(Thread::current(), sleep_time_ms, false);
SuspendibleThreadSet::join();
}
- double end_time2_sec = os::elapsedTime();
- double elapsed_time2_sec = end_time2_sec - start_time_sec;
-
-#if 0
- gclog_or_tty->print_cr("CM: elapsed %1.4lf ms, sleep %1.4lf ms, "
- "overhead %1.4lf",
- elapsed_vtime_sec * 1000.0, (double) sleep_time_ms,
- the_task->conc_overhead(os::elapsedTime()) * 8.0);
- gclog_or_tty->print_cr("elapsed time %1.4lf ms, time 2: %1.4lf ms",
- elapsed_time_sec * 1000.0, elapsed_time2_sec * 1000.0);
-#endif
} while (!_cm->has_aborted() && the_task->has_aborted());
}
the_task->record_end_time();
@@ -1409,7 +1400,7 @@
void set_bit_for_region(HeapRegion* hr) {
assert(!hr->continuesHumongous(), "should have filtered those out");
- BitMap::idx_t index = (BitMap::idx_t) hr->hrs_index();
+ BitMap::idx_t index = (BitMap::idx_t) hr->hrm_index();
if (!hr->startsHumongous()) {
// Normal (non-humongous) case: just set the bit.
_region_bm->par_at_put(index, true);
@@ -1597,7 +1588,7 @@
if (_verbose) {
gclog_or_tty->print_cr("Region %u: marked bytes mismatch: "
"expected: " SIZE_FORMAT ", actual: " SIZE_FORMAT,
- hr->hrs_index(), exp_marked_bytes, act_marked_bytes);
+ hr->hrm_index(), exp_marked_bytes, act_marked_bytes);
}
failures += 1;
}
@@ -1606,7 +1597,7 @@
// (which was just calculated) region bit maps.
// We're not OK if the bit in the calculated expected region
// bitmap is set and the bit in the actual region bitmap is not.
- BitMap::idx_t index = (BitMap::idx_t) hr->hrs_index();
+ BitMap::idx_t index = (BitMap::idx_t) hr->hrm_index();
bool expected = _exp_region_bm->at(index);
bool actual = _region_bm->at(index);
@@ -1614,7 +1605,7 @@
if (_verbose) {
gclog_or_tty->print_cr("Region %u: region bitmap mismatch: "
"expected: %s, actual: %s",
- hr->hrs_index(),
+ hr->hrm_index(),
BOOL_TO_STR(expected), BOOL_TO_STR(actual));
}
failures += 1;
@@ -1635,7 +1626,7 @@
if (_verbose) {
gclog_or_tty->print_cr("Region %u: card bitmap mismatch at " SIZE_FORMAT ": "
"expected: %s, actual: %s",
- hr->hrs_index(), i,
+ hr->hrm_index(), i,
BOOL_TO_STR(expected), BOOL_TO_STR(actual));
}
failures += 1;
@@ -2949,11 +2940,6 @@
_nextMarkBitMap->clearRange(mr);
}
-void ConcurrentMark::clearRangeBothBitmaps(MemRegion mr) {
- clearRangePrevBitmap(mr);
- clearRangeNextBitmap(mr);
-}
-
HeapRegion*
ConcurrentMark::claim_region(uint worker_id) {
// "checkpoint" the finger
@@ -3256,7 +3242,7 @@
assert(limit_idx <= end_idx, "or else use atomics");
// Aggregate the "stripe" in the count data associated with hr.
- uint hrs_index = hr->hrs_index();
+ uint hrm_index = hr->hrm_index();
size_t marked_bytes = 0;
for (uint i = 0; i < _max_worker_id; i += 1) {
@@ -3265,7 +3251,7 @@
// Fetch the marked_bytes in this region for task i and
// add it to the running total for this region.
- marked_bytes += marked_bytes_array[hrs_index];
+ marked_bytes += marked_bytes_array[hrm_index];
// Now union the bitmaps[0,max_worker_id)[start_idx..limit_idx)
// into the global card bitmap.
@@ -3499,17 +3485,6 @@
}
}
-bool ConcurrentMark::containing_card_is_marked(void* p) {
- size_t offset = pointer_delta(p, _g1h->reserved_region().start(), 1);
- return _card_bm.at(offset >> CardTableModRefBS::card_shift);
-}
-
-bool ConcurrentMark::containing_cards_are_marked(void* start,
- void* last) {
- return containing_card_is_marked(start) &&
- containing_card_is_marked(last);
-}
-
#ifndef PRODUCT
// for debugging purposes
void ConcurrentMark::print_finger() {
@@ -3762,7 +3737,7 @@
if (_cm->verbose_medium()) {
gclog_or_tty->print_cr("[%u] regular clock, interval = %1.2lfms, "
- "scanned = %d%s, refs reached = %d%s",
+ "scanned = "SIZE_FORMAT"%s, refs reached = "SIZE_FORMAT"%s",
_worker_id, last_interval_ms,
_words_scanned,
(_words_scanned >= _words_scanned_limit) ? " (*)" : "",
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -683,7 +683,9 @@
return _task_queues->steal(worker_id, hash_seed, obj);
}
- ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* prev_bitmap_storage, G1RegionToSpaceMapper* next_bitmap_storage);
+ ConcurrentMark(G1CollectedHeap* g1h,
+ G1RegionToSpaceMapper* prev_bitmap_storage,
+ G1RegionToSpaceMapper* next_bitmap_storage);
~ConcurrentMark();
ConcurrentMarkThread* cmThread() { return _cmThread; }
@@ -712,8 +714,10 @@
// inconsistent) and always passing the size. hr is the region that
// contains the object and it's passed optionally from callers who
// might already have it (no point in recalculating it).
- inline void grayRoot(oop obj, size_t word_size,
- uint worker_id, HeapRegion* hr = NULL);
+ inline void grayRoot(oop obj,
+ size_t word_size,
+ uint worker_id,
+ HeapRegion* hr = NULL);
// It iterates over the heap and for each object it comes across it
// will dump the contents of its reference fields, as well as
@@ -734,7 +738,8 @@
// AND MARKED : indicates that an object is both explicitly and
// implicitly live (it should be one or the other, not both)
void print_reachable(const char* str,
- VerifyOption vo, bool all) PRODUCT_RETURN;
+ VerifyOption vo,
+ bool all) PRODUCT_RETURN;
// Clear the next marking bitmap (will be called concurrently).
void clearNextBitmap();
@@ -771,12 +776,11 @@
// this carefully!
inline void markPrev(oop p);
- // Clears marks for all objects in the given range, for the prev,
- // next, or both bitmaps. NB: the previous bitmap is usually
+ // Clears marks for all objects in the given range, for the prev or
+ // next bitmaps. NB: the previous bitmap is usually
// read-only, so use this carefully!
void clearRangePrevBitmap(MemRegion mr);
void clearRangeNextBitmap(MemRegion mr);
- void clearRangeBothBitmaps(MemRegion mr);
// Notify data structures that a GC has started.
void note_start_of_gc() {
@@ -798,21 +802,6 @@
bool verify_thread_buffers,
bool verify_fingers) PRODUCT_RETURN;
- bool isMarked(oop p) const {
- assert(p != NULL && p->is_oop(), "expected an oop");
- HeapWord* addr = (HeapWord*)p;
- assert(addr >= _nextMarkBitMap->startWord() ||
- addr < _nextMarkBitMap->endWord(), "in a region");
-
- return _nextMarkBitMap->isMarked(addr);
- }
-
- inline bool not_yet_marked(oop p) const;
-
- // XXX Debug code
- bool containing_card_is_marked(void* p);
- bool containing_cards_are_marked(void* start, void* last);
-
bool isPrevMarked(oop p) const {
assert(p != NULL && p->is_oop(), "expected an oop");
HeapWord* addr = (HeapWord*)p;
@@ -898,7 +887,8 @@
// marked_bytes array slot for the given HeapRegion.
// Sets the bits in the given card bitmap that are associated with the
// cards that are spanned by the memory region.
- inline void count_region(MemRegion mr, HeapRegion* hr,
+ inline void count_region(MemRegion mr,
+ HeapRegion* hr,
size_t* marked_bytes_array,
BitMap* task_card_bm);
@@ -906,56 +896,27 @@
// data structures for the given worker id.
inline void count_region(MemRegion mr, HeapRegion* hr, uint worker_id);
- // Counts the given memory region in the task/worker counting
- // data structures for the given worker id.
- inline void count_region(MemRegion mr, uint worker_id);
-
// Counts the given object in the given task/worker counting
// data structures.
- inline void count_object(oop obj, HeapRegion* hr,
+ inline void count_object(oop obj,
+ HeapRegion* hr,
size_t* marked_bytes_array,
BitMap* task_card_bm);
- // Counts the given object in the task/worker counting data
- // structures for the given worker id.
- inline void count_object(oop obj, HeapRegion* hr, uint worker_id);
-
// Attempts to mark the given object and, if successful, counts
// the object in the given task/worker counting structures.
- inline bool par_mark_and_count(oop obj, HeapRegion* hr,
+ inline bool par_mark_and_count(oop obj,
+ HeapRegion* hr,
size_t* marked_bytes_array,
BitMap* task_card_bm);
// Attempts to mark the given object and, if successful, counts
// the object in the task/worker counting structures for the
// given worker id.
- inline bool par_mark_and_count(oop obj, size_t word_size,
- HeapRegion* hr, uint worker_id);
-
- // Attempts to mark the given object and, if successful, counts
- // the object in the task/worker counting structures for the
- // given worker id.
- inline bool par_mark_and_count(oop obj, HeapRegion* hr, uint worker_id);
-
- // Similar to the above routine but we don't know the heap region that
- // contains the object to be marked/counted, which this routine looks up.
- inline bool par_mark_and_count(oop obj, uint worker_id);
-
- // Similar to the above routine but there are times when we cannot
- // safely calculate the size of obj due to races and we, therefore,
- // pass the size in as a parameter. It is the caller's responsibility
- // to ensure that the size passed in for obj is valid.
- inline bool par_mark_and_count(oop obj, size_t word_size, uint worker_id);
-
- // Unconditionally mark the given object, and unconditionally count
- // the object in the counting structures for worker id 0.
- // Should *not* be called from parallel code.
- inline bool mark_and_count(oop obj, HeapRegion* hr);
-
- // Similar to the above routine but we don't know the heap region that
- // contains the object to be marked/counted, which this routine looks up.
- // Should *not* be called from parallel code.
- inline bool mark_and_count(oop obj);
+ inline bool par_mark_and_count(oop obj,
+ size_t word_size,
+ HeapRegion* hr,
+ uint worker_id);
// Returns true if initialization was successfully completed.
bool completed_initialization() const {
@@ -1227,9 +1188,12 @@
_finger = new_finger;
}
- CMTask(uint worker_id, ConcurrentMark *cm,
- size_t* marked_bytes, BitMap* card_bm,
- CMTaskQueue* task_queue, CMTaskQueueSet* task_queues);
+ CMTask(uint worker_id,
+ ConcurrentMark *cm,
+ size_t* marked_bytes,
+ BitMap* card_bm,
+ CMTaskQueue* task_queue,
+ CMTaskQueueSet* task_queues);
// it prints statistics associated with this task
void print_stats();
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -86,7 +86,7 @@
HeapWord* start = mr.start();
HeapWord* end = mr.end();
size_t region_size_bytes = mr.byte_size();
- uint index = hr->hrs_index();
+ uint index = hr->hrm_index();
assert(!hr->continuesHumongous(), "should not be HC region");
assert(hr == g1h->heap_region_containing(start), "sanity");
@@ -125,14 +125,6 @@
count_region(mr, hr, marked_bytes_array, task_card_bm);
}
-// Counts the given memory region, which may be a single object, in the
-// task/worker counting data structures for the given worker id.
-inline void ConcurrentMark::count_region(MemRegion mr, uint worker_id) {
- HeapWord* addr = mr.start();
- HeapRegion* hr = _g1h->heap_region_containing_raw(addr);
- count_region(mr, hr, worker_id);
-}
-
// Counts the given object in the given task/worker counting data structures.
inline void ConcurrentMark::count_object(oop obj,
HeapRegion* hr,
@@ -142,17 +134,6 @@
count_region(mr, hr, marked_bytes_array, task_card_bm);
}
-// Counts the given object in the task/worker counting data
-// structures for the given worker id.
-inline void ConcurrentMark::count_object(oop obj,
- HeapRegion* hr,
- uint worker_id) {
- size_t* marked_bytes_array = count_marked_bytes_array_for(worker_id);
- BitMap* task_card_bm = count_card_bitmap_for(worker_id);
- HeapWord* addr = (HeapWord*) obj;
- count_object(obj, hr, marked_bytes_array, task_card_bm);
-}
-
// Attempts to mark the given object and, if successful, counts
// the object in the given task/worker counting structures.
inline bool ConcurrentMark::par_mark_and_count(oop obj,
@@ -184,63 +165,6 @@
return false;
}
-// Attempts to mark the given object and, if successful, counts
-// the object in the task/worker counting structures for the
-// given worker id.
-inline bool ConcurrentMark::par_mark_and_count(oop obj,
- HeapRegion* hr,
- uint worker_id) {
- HeapWord* addr = (HeapWord*)obj;
- if (_nextMarkBitMap->parMark(addr)) {
- // Update the task specific count data for the object.
- count_object(obj, hr, worker_id);
- return true;
- }
- return false;
-}
-
-// As above - but we don't know the heap region containing the
-// object and so have to supply it.
-inline bool ConcurrentMark::par_mark_and_count(oop obj, uint worker_id) {
- HeapWord* addr = (HeapWord*)obj;
- HeapRegion* hr = _g1h->heap_region_containing_raw(addr);
- return par_mark_and_count(obj, hr, worker_id);
-}
-
-// Similar to the above routine but we already know the size, in words, of
-// the object that we wish to mark/count
-inline bool ConcurrentMark::par_mark_and_count(oop obj,
- size_t word_size,
- uint worker_id) {
- HeapWord* addr = (HeapWord*)obj;
- if (_nextMarkBitMap->parMark(addr)) {
- // Update the task specific count data for the object.
- MemRegion mr(addr, word_size);
- count_region(mr, worker_id);
- return true;
- }
- return false;
-}
-
-// Unconditionally mark the given object, and unconditionally count
-// the object in the counting structures for worker id 0.
-// Should *not* be called from parallel code.
-inline bool ConcurrentMark::mark_and_count(oop obj, HeapRegion* hr) {
- HeapWord* addr = (HeapWord*)obj;
- _nextMarkBitMap->mark(addr);
- // Update the task specific count data for the object.
- count_object(obj, hr, 0 /* worker_id */);
- return true;
-}
-
-// As above - but we don't have the heap region containing the
-// object, so we have to supply it.
-inline bool ConcurrentMark::mark_and_count(oop obj) {
- HeapWord* addr = (HeapWord*)obj;
- HeapRegion* hr = _g1h->heap_region_containing_raw(addr);
- return mark_and_count(obj, hr);
-}
-
inline bool CMBitMapRO::iterate(BitMapClosure* cl, MemRegion mr) {
HeapWord* start_addr = MAX2(startWord(), mr.start());
HeapWord* end_addr = MIN2(endWord(), mr.end());
--- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -30,14 +30,7 @@
#include "runtime/java.hpp"
#include "services/memTracker.hpp"
-PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
-void G1BlockOffsetSharedArrayMappingChangedListener::on_commit(uint start_idx, size_t num_regions) {
- // Nothing to do. The BOT is hard-wired to be part of the HeapRegion, and we cannot
- // retrieve it here since this would cause firing of several asserts. The code
- // executed after commit of a region already needs to do some re-initialization of
- // the HeapRegion, so we combine that.
-}
//////////////////////////////////////////////////////////////////////
// G1BlockOffsetSharedArray
@@ -59,10 +52,10 @@
if (TraceBlockOffsetTable) {
gclog_or_tty->print_cr("G1BlockOffsetSharedArray::G1BlockOffsetSharedArray: ");
gclog_or_tty->print_cr(" "
- " rs.base(): " INTPTR_FORMAT
- " rs.size(): " INTPTR_FORMAT
- " rs end(): " INTPTR_FORMAT,
- bot_reserved.start(), bot_reserved.byte_size(), bot_reserved.end());
+ " rs.base(): " PTR_FORMAT
+ " rs.size(): " SIZE_FORMAT
+ " rs end(): " PTR_FORMAT,
+ p2i(bot_reserved.start()), bot_reserved.byte_size(), p2i(bot_reserved.end()));
}
}
@@ -72,26 +65,16 @@
return (delta & right_n_bits(LogN_words)) == (size_t)NoBits;
}
-void G1BlockOffsetSharedArray::set_offset_array(HeapWord* left, HeapWord* right, u_char offset) {
- set_offset_array(index_for(left), index_for(right -1), offset);
-}
-
//////////////////////////////////////////////////////////////////////
// G1BlockOffsetArray
//////////////////////////////////////////////////////////////////////
G1BlockOffsetArray::G1BlockOffsetArray(G1BlockOffsetSharedArray* array,
- MemRegion mr, bool init_to_zero) :
+ MemRegion mr) :
G1BlockOffsetTable(mr.start(), mr.end()),
_unallocated_block(_bottom),
- _array(array), _gsp(NULL),
- _init_to_zero(init_to_zero) {
+ _array(array), _gsp(NULL) {
assert(_bottom <= _end, "arguments out of order");
- if (!_init_to_zero) {
- // initialize cards to point back to mr.start()
- set_remainder_to_point_to_start(mr.start() + N_words, mr.end());
- _array->set_offset_array(0, 0); // set first card to 0
- }
}
void G1BlockOffsetArray::set_space(G1OffsetTableContigSpace* sp) {
@@ -181,93 +164,6 @@
DEBUG_ONLY(check_all_cards(start_card, end_card);)
}
-// The block [blk_start, blk_end) has been allocated;
-// adjust the block offset table to represent this information;
-// right-open interval: [blk_start, blk_end)
-void
-G1BlockOffsetArray::alloc_block(HeapWord* blk_start, HeapWord* blk_end) {
- mark_block(blk_start, blk_end);
- allocated(blk_start, blk_end);
-}
-
-// Adjust BOT to show that a previously whole block has been split
-// into two.
-void G1BlockOffsetArray::split_block(HeapWord* blk, size_t blk_size,
- size_t left_blk_size) {
- // Verify that the BOT shows [blk, blk + blk_size) to be one block.
- verify_single_block(blk, blk_size);
- // Update the BOT to indicate that [blk + left_blk_size, blk + blk_size)
- // is one single block.
- mark_block(blk + left_blk_size, blk + blk_size);
-}
-
-
-// Action_mark - update the BOT for the block [blk_start, blk_end).
-// Current typical use is for splitting a block.
-// Action_single - update the BOT for an allocation.
-// Action_verify - BOT verification.
-void G1BlockOffsetArray::do_block_internal(HeapWord* blk_start,
- HeapWord* blk_end,
- Action action) {
- assert(Universe::heap()->is_in_reserved(blk_start),
- "reference must be into the heap");
- assert(Universe::heap()->is_in_reserved(blk_end-1),
- "limit must be within the heap");
- // This is optimized to make the test fast, assuming we only rarely
- // cross boundaries.
- uintptr_t end_ui = (uintptr_t)(blk_end - 1);
- uintptr_t start_ui = (uintptr_t)blk_start;
- // Calculate the last card boundary preceding end of blk
- intptr_t boundary_before_end = (intptr_t)end_ui;
- clear_bits(boundary_before_end, right_n_bits(LogN));
- if (start_ui <= (uintptr_t)boundary_before_end) {
- // blk starts at or crosses a boundary
- // Calculate index of card on which blk begins
- size_t start_index = _array->index_for(blk_start);
- // Index of card on which blk ends
- size_t end_index = _array->index_for(blk_end - 1);
- // Start address of card on which blk begins
- HeapWord* boundary = _array->address_for_index(start_index);
- assert(boundary <= blk_start, "blk should start at or after boundary");
- if (blk_start != boundary) {
- // blk starts strictly after boundary
- // adjust card boundary and start_index forward to next card
- boundary += N_words;
- start_index++;
- }
- assert(start_index <= end_index, "monotonicity of index_for()");
- assert(boundary <= (HeapWord*)boundary_before_end, "tautology");
- switch (action) {
- case Action_mark: {
- if (init_to_zero()) {
- _array->set_offset_array(start_index, boundary, blk_start);
- break;
- } // Else fall through to the next case
- }
- case Action_single: {
- _array->set_offset_array(start_index, boundary, blk_start);
- // We have finished marking the "offset card". We need to now
- // mark the subsequent cards that this blk spans.
- if (start_index < end_index) {
- HeapWord* rem_st = _array->address_for_index(start_index) + N_words;
- HeapWord* rem_end = _array->address_for_index(end_index) + N_words;
- set_remainder_to_point_to_start(rem_st, rem_end);
- }
- break;
- }
- case Action_check: {
- _array->check_offset_array(start_index, boundary, blk_start);
- // We have finished checking the "offset card". We need to now
- // check the subsequent cards that this blk spans.
- check_all_cards(start_index + 1, end_index);
- break;
- }
- default:
- ShouldNotReachHere();
- }
- }
-}
-
// The card-interval [start_card, end_card] is a closed interval; this
// is an expensive check -- use with care and only under protection of
// suitable flag.
@@ -306,25 +202,6 @@
}
}
-// The range [blk_start, blk_end) represents a single contiguous block
-// of storage; modify the block offset table to represent this
-// information; Right-open interval: [blk_start, blk_end)
-// NOTE: this method does _not_ adjust _unallocated_block.
-void
-G1BlockOffsetArray::single_block(HeapWord* blk_start, HeapWord* blk_end) {
- do_block_internal(blk_start, blk_end, Action_single);
-}
-
-// Mark the BOT such that if [blk_start, blk_end) straddles a card
-// boundary, the card following the first such boundary is marked
-// with the appropriate offset.
-// NOTE: this method does _not_ adjust _unallocated_block or
-// any cards subsequent to the first one.
-void
-G1BlockOffsetArray::mark_block(HeapWord* blk_start, HeapWord* blk_end) {
- do_block_internal(blk_start, blk_end, Action_mark);
-}
-
HeapWord* G1BlockOffsetArray::block_start_unsafe(const void* addr) {
assert(_bottom <= addr && addr < _end,
"addr must be covered by this Array");
@@ -381,7 +258,7 @@
assert(next_boundary <= _array->_end,
err_msg("next_boundary is beyond the end of the covered region "
" next_boundary " PTR_FORMAT " _array->_end " PTR_FORMAT,
- next_boundary, _array->_end));
+ p2i(next_boundary), p2i(_array->_end)));
if (addr >= gsp()->top()) return gsp()->top();
while (next_boundary < addr) {
while (n <= next_boundary) {
@@ -397,57 +274,13 @@
return forward_to_block_containing_addr_const(q, n, addr);
}
-HeapWord* G1BlockOffsetArray::block_start_careful(const void* addr) const {
- assert(_array->offset_array(0) == 0, "objects can't cross covered areas");
-
- assert(_bottom <= addr && addr < _end,
- "addr must be covered by this Array");
- // Must read this exactly once because it can be modified by parallel
- // allocation.
- HeapWord* ub = _unallocated_block;
- if (BlockOffsetArrayUseUnallocatedBlock && addr >= ub) {
- assert(ub < _end, "tautology (see above)");
- return ub;
- }
-
- // Otherwise, find the block start using the table, but taking
- // care (cf block_start_unsafe() above) not to parse any objects/blocks
- // on the cards themselves.
- size_t index = _array->index_for(addr);
- assert(_array->address_for_index(index) == addr,
- "arg should be start of card");
-
- HeapWord* q = (HeapWord*)addr;
- uint offset;
- do {
- offset = _array->offset_array(index--);
- q -= offset;
- } while (offset == N_words);
- assert(q <= addr, "block start should be to left of arg");
- return q;
-}
-
// Note that the committed size of the covered space may have changed,
// so the table size might also wish to change.
void G1BlockOffsetArray::resize(size_t new_word_size) {
HeapWord* new_end = _bottom + new_word_size;
- if (_end < new_end && !init_to_zero()) {
- // verify that the old and new boundaries are also card boundaries
- assert(_array->is_card_boundary(_end),
- "_end not a card boundary");
- assert(_array->is_card_boundary(new_end),
- "new _end would not be a card boundary");
- // set all the newly added cards
- _array->set_offset_array(_end, new_end, N_words);
- }
_end = new_end; // update _end
}
-void G1BlockOffsetArray::set_region(MemRegion mr) {
- _bottom = mr.start();
- _end = mr.end();
-}
-
//
// threshold_
// | _index_
@@ -522,7 +355,7 @@
"blk_start: " PTR_FORMAT ", "
"boundary: " PTR_FORMAT,
(uint)_array->offset_array(orig_index),
- blk_start, boundary));
+ p2i(blk_start), p2i(boundary)));
for (size_t j = orig_index + 1; j <= end_index; j++) {
assert(_array->offset_array(j) > 0 &&
_array->offset_array(j) <=
@@ -556,9 +389,9 @@
"card addr: "PTR_FORMAT" BOT entry: %u "
"obj: "PTR_FORMAT" word size: "SIZE_FORMAT" "
"cards: ["SIZE_FORMAT","SIZE_FORMAT"]",
- block_start, card, card_addr,
+ p2i(block_start), card, p2i(card_addr),
_array->offset_array(card),
- obj_start, word_size, first_card, last_card);
+ p2i(obj_start), word_size, first_card, last_card);
return false;
}
}
@@ -572,10 +405,10 @@
size_t to_index = _array->index_for(_end);
out->print_cr(">> BOT for area ["PTR_FORMAT","PTR_FORMAT") "
"cards ["SIZE_FORMAT","SIZE_FORMAT")",
- _bottom, _end, from_index, to_index);
+ p2i(_bottom), p2i(_end), from_index, to_index);
for (size_t i = from_index; i < to_index; ++i) {
out->print_cr(" entry "SIZE_FORMAT_W(8)" | "PTR_FORMAT" : %3u",
- i, _array->address_for_index(i),
+ i, p2i(_array->address_for_index(i)),
(uint) _array->offset_array(i));
}
}
@@ -606,7 +439,7 @@
G1BlockOffsetArrayContigSpace::
G1BlockOffsetArrayContigSpace(G1BlockOffsetSharedArray* array,
MemRegion mr) :
- G1BlockOffsetArray(array, mr, true)
+ G1BlockOffsetArray(array, mr)
{
_next_offset_threshold = NULL;
_next_offset_index = 0;
@@ -641,15 +474,6 @@
return _next_offset_threshold;
}
-void G1BlockOffsetArrayContigSpace::zero_bottom_entry() {
- assert(!Universe::heap()->is_in_reserved(_array->_offset_array),
- "just checking");
- size_t bottom_index = _array->index_for(_bottom);
- assert(_array->address_for_index(bottom_index) == _bottom,
- "Precondition of call");
- _array->set_offset_array(bottom_index, 0);
-}
-
void
G1BlockOffsetArrayContigSpace::set_for_starts_humongous(HeapWord* new_top) {
assert(new_top <= _end, "_end should have already been updated");
@@ -663,7 +487,7 @@
void
G1BlockOffsetArrayContigSpace::print_on(outputStream* out) {
G1BlockOffsetArray::print_on(out);
- out->print_cr(" next offset threshold: "PTR_FORMAT, _next_offset_threshold);
+ out->print_cr(" next offset threshold: "PTR_FORMAT, p2i(_next_offset_threshold));
out->print_cr(" next offset index: "SIZE_FORMAT, _next_offset_index);
}
#endif // !PRODUCT
--- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -109,7 +109,12 @@
class G1BlockOffsetSharedArrayMappingChangedListener : public G1MappingChangedListener {
public:
- virtual void on_commit(uint start_idx, size_t num_regions);
+ virtual void on_commit(uint start_idx, size_t num_regions) {
+ // Nothing to do. The BOT is hard-wired to be part of the HeapRegion, and we cannot
+ // retrieve it here since this would cause firing of several asserts. The code
+ // executed after commit of a region already needs to do some re-initialization of
+ // the HeapRegion, so we combine that.
+ }
};
// This implementation of "G1BlockOffsetTable" divides the covered region
@@ -153,8 +158,6 @@
// For performance these have to devolve to array accesses in product builds.
inline u_char offset_array(size_t index) const;
- void set_offset_array(HeapWord* left, HeapWord* right, u_char offset);
-
void set_offset_array_raw(size_t index, u_char offset) {
_offset_array[index] = offset;
}
@@ -165,8 +168,6 @@
inline void set_offset_array(size_t left, size_t right, u_char offset);
- inline void check_offset_array(size_t index, HeapWord* high, HeapWord* low) const;
-
bool is_card_boundary(HeapWord* p) const;
public:
@@ -193,8 +194,6 @@
// G1BlockOffsetTable(s) to initialize cards.
G1BlockOffsetSharedArray(MemRegion heap, G1RegionToSpaceMapper* storage);
- void set_bottom(HeapWord* new_bottom);
-
// Return the appropriate index into "_offset_array" for "p".
inline size_t index_for(const void* p) const;
inline size_t index_for_raw(const void* p) const;
@@ -220,14 +219,6 @@
LogN = G1BlockOffsetSharedArray::LogN
};
- // The following enums are used by do_block_helper
- enum Action {
- Action_single, // BOT records a single block (see single_block())
- Action_mark, // BOT marks the start of a block (see mark_block())
- Action_check // Check that BOT records block correctly
- // (see verify_single_block()).
- };
-
// This is the array, which can be shared by several BlockOffsetArray's
// servicing different
G1BlockOffsetSharedArray* _array;
@@ -235,10 +226,6 @@
// The space that owns this subregion.
G1OffsetTableContigSpace* _gsp;
- // If true, array entries are initialized to 0; otherwise, they are
- // initialized to point backwards to the beginning of the covered region.
- bool _init_to_zero;
-
// The portion [_unallocated_block, _sp.end()) of the space that
// is a single block known not to contain any objects.
// NOTE: See BlockOffsetArrayUseUnallocatedBlock flag.
@@ -253,9 +240,6 @@
// that is closed: [start_index, end_index]
void set_remainder_to_point_to_start_incl(size_t start, size_t end);
- // A helper function for BOT adjustment/verification work
- void do_block_internal(HeapWord* blk_start, HeapWord* blk_end, Action action);
-
protected:
G1OffsetTableContigSpace* gsp() const { return _gsp; }
@@ -303,11 +287,9 @@
public:
// The space may not have it's bottom and top set yet, which is why the
- // region is passed as a parameter. If "init_to_zero" is true, the
- // elements of the array are initialized to zero. Otherwise, they are
- // initialized to point backwards to the beginning.
- G1BlockOffsetArray(G1BlockOffsetSharedArray* array, MemRegion mr,
- bool init_to_zero);
+ // region is passed as a parameter. The elements of the array are
+ // initialized to zero.
+ G1BlockOffsetArray(G1BlockOffsetSharedArray* array, MemRegion mr);
// Note: this ought to be part of the constructor, but that would require
// "this" to be passed as a parameter to a member constructor for
@@ -315,114 +297,19 @@
// This would be legal C++, but MS VC++ doesn't allow it.
void set_space(G1OffsetTableContigSpace* sp);
- // Resets the covered region to the given "mr".
- void set_region(MemRegion mr);
-
// Resets the covered region to one with the same _bottom as before but
// the "new_word_size".
void resize(size_t new_word_size);
- // These must be guaranteed to work properly (i.e., do nothing)
- // when "blk_start" ("blk" for second version) is "NULL".
- virtual void alloc_block(HeapWord* blk_start, HeapWord* blk_end);
- virtual void alloc_block(HeapWord* blk, size_t size) {
- alloc_block(blk, blk + size);
- }
-
- // The following methods are useful and optimized for a
- // general, non-contiguous space.
-
- // Given a block [blk_start, blk_start + full_blk_size), and
- // a left_blk_size < full_blk_size, adjust the BOT to show two
- // blocks [blk_start, blk_start + left_blk_size) and
- // [blk_start + left_blk_size, blk_start + full_blk_size).
- // It is assumed (and verified in the non-product VM) that the
- // BOT was correct for the original block.
- void split_block(HeapWord* blk_start, size_t full_blk_size,
- size_t left_blk_size);
-
- // Adjust the BOT to show that it has a single block in the
- // range [blk_start, blk_start + size). All necessary BOT
- // cards are adjusted, but _unallocated_block isn't.
- void single_block(HeapWord* blk_start, HeapWord* blk_end);
- void single_block(HeapWord* blk, size_t size) {
- single_block(blk, blk + size);
- }
-
- // Adjust BOT to show that it has a block in the range
- // [blk_start, blk_start + size). Only the first card
- // of BOT is touched. It is assumed (and verified in the
- // non-product VM) that the remaining cards of the block
- // are correct.
- void mark_block(HeapWord* blk_start, HeapWord* blk_end);
- void mark_block(HeapWord* blk, size_t size) {
- mark_block(blk, blk + size);
- }
-
- // Adjust _unallocated_block to indicate that a particular
- // block has been newly allocated or freed. It is assumed (and
- // verified in the non-product VM) that the BOT is correct for
- // the given block.
- inline void allocated(HeapWord* blk_start, HeapWord* blk_end) {
- // Verify that the BOT shows [blk, blk + blk_size) to be one block.
- verify_single_block(blk_start, blk_end);
- if (BlockOffsetArrayUseUnallocatedBlock) {
- _unallocated_block = MAX2(_unallocated_block, blk_end);
- }
- }
-
- inline void allocated(HeapWord* blk, size_t size) {
- allocated(blk, blk + size);
- }
-
- inline void freed(HeapWord* blk_start, HeapWord* blk_end);
-
- inline void freed(HeapWord* blk, size_t size);
-
virtual HeapWord* block_start_unsafe(const void* addr);
virtual HeapWord* block_start_unsafe_const(const void* addr) const;
- // Requires "addr" to be the start of a card and returns the
- // start of the block that contains the given address.
- HeapWord* block_start_careful(const void* addr) const;
-
- // If true, initialize array slots with no allocated blocks to zero.
- // Otherwise, make them point back to the front.
- bool init_to_zero() { return _init_to_zero; }
-
- // Verification & debugging - ensure that the offset table reflects the fact
- // that the block [blk_start, blk_end) or [blk, blk + size) is a
- // single block of storage. NOTE: can;t const this because of
- // call to non-const do_block_internal() below.
- inline void verify_single_block(HeapWord* blk_start, HeapWord* blk_end) {
- if (VerifyBlockOffsetArray) {
- do_block_internal(blk_start, blk_end, Action_check);
- }
- }
-
- inline void verify_single_block(HeapWord* blk, size_t size) {
- verify_single_block(blk, blk + size);
- }
-
// Used by region verification. Checks that the contents of the
// BOT reflect that there's a single object that spans the address
// range [obj_start, obj_start + word_size); returns true if this is
// the case, returns false if it's not.
bool verify_for_object(HeapWord* obj_start, size_t word_size) const;
- // Verify that the given block is before _unallocated_block
- inline void verify_not_unallocated(HeapWord* blk_start,
- HeapWord* blk_end) const {
- if (BlockOffsetArrayUseUnallocatedBlock) {
- assert(blk_start < blk_end, "Block inconsistency?");
- assert(blk_end <= _unallocated_block, "_unallocated_block problem");
- }
- }
-
- inline void verify_not_unallocated(HeapWord* blk, size_t size) const {
- verify_not_unallocated(blk, blk + size);
- }
-
void check_all_cards(size_t left_card, size_t right_card) const;
virtual void print_on(outputStream* out) PRODUCT_RETURN;
@@ -445,14 +332,12 @@
blk_start, blk_end);
}
- // Variant of zero_bottom_entry that does not check for availability of the
+ // Zero out the entry for _bottom (offset will be zero). Does not check for availability of the
// memory first.
void zero_bottom_entry_raw();
// Variant of initialize_threshold that does not check for availability of the
// memory first.
HeapWord* initialize_threshold_raw();
- // Zero out the entry for _bottom (offset will be zero).
- void zero_bottom_entry();
public:
G1BlockOffsetArrayContigSpace(G1BlockOffsetSharedArray* array, MemRegion mr);
--- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -91,13 +91,6 @@
}
}
-void G1BlockOffsetSharedArray::check_offset_array(size_t index, HeapWord* high, HeapWord* low) const {
- check_index(index, "index out of range");
- assert(high >= low, "addresses out of order");
- check_offset(pointer_delta(high, low), "offset too large");
- assert(_offset_array[index] == pointer_delta(high, low), "Wrong offset");
-}
-
// Variant of index_for that does not check the index for validity.
inline size_t G1BlockOffsetSharedArray::index_for_raw(const void* p) const {
return pointer_delta((char*)p, _reserved.start(), sizeof(char)) >> LogN;
@@ -193,28 +186,4 @@
return q;
}
-//////////////////////////////////////////////////////////////////////////
-// BlockOffsetArrayNonContigSpace inlines
-//////////////////////////////////////////////////////////////////////////
-inline void G1BlockOffsetArray::freed(HeapWord* blk_start, HeapWord* blk_end) {
- // Verify that the BOT shows [blk_start, blk_end) to be one block.
- verify_single_block(blk_start, blk_end);
- // adjust _unallocated_block upward or downward
- // as appropriate
- if (BlockOffsetArrayUseUnallocatedBlock) {
- assert(_unallocated_block <= _end,
- "Inconsistent value for _unallocated_block");
- if (blk_end >= _unallocated_block && blk_start <= _unallocated_block) {
- // CMS-specific note: a block abutting _unallocated_block to
- // its left is being freed, a new block is being added or
- // we are resetting following a compaction
- _unallocated_block = blk_start;
- }
- }
-}
-
-inline void G1BlockOffsetArray::freed(HeapWord* blk, size_t size) {
- freed(blk, blk + size);
-}
-
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1BLOCKOFFSETTABLE_INLINE_HPP
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -532,9 +532,9 @@
// again to allocate from it.
append_secondary_free_list();
- assert(_hrs.num_free_regions() > 0, "if the secondary_free_list was not "
+ assert(_hrm.num_free_regions() > 0, "if the secondary_free_list was not "
"empty we should have moved at least one entry to the free_list");
- HeapRegion* res = _hrs.allocate_free_region(is_old);
+ HeapRegion* res = _hrm.allocate_free_region(is_old);
if (G1ConcRegionFreeingVerbose) {
gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : "
"allocated "HR_FORMAT" from secondary_free_list",
@@ -575,7 +575,7 @@
}
}
- res = _hrs.allocate_free_region(is_old);
+ res = _hrm.allocate_free_region(is_old);
if (res == NULL) {
if (G1ConcRegionFreeingVerbose) {
@@ -601,7 +601,7 @@
// always expand the heap by an amount aligned to the heap
// region size, the free list should in theory not be empty.
// In either case allocate_free_region() will check for NULL.
- res = _hrs.allocate_free_region(is_old);
+ res = _hrm.allocate_free_region(is_old);
} else {
_expand_heap_after_alloc_failure = false;
}
@@ -613,7 +613,7 @@
G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first,
uint num_regions,
size_t word_size) {
- assert(first != G1_NO_HRS_INDEX, "pre-condition");
+ assert(first != G1_NO_HRM_INDEX, "pre-condition");
assert(isHumongous(word_size), "word_size should be humongous");
assert(num_regions * HeapRegion::GrainWords >= word_size, "pre-condition");
@@ -751,7 +751,7 @@
verify_region_sets_optional();
- uint first = G1_NO_HRS_INDEX;
+ uint first = G1_NO_HRM_INDEX;
uint obj_regions = (uint)(align_size_up_(word_size, HeapRegion::GrainWords) / HeapRegion::GrainWords);
if (obj_regions == 1) {
@@ -760,7 +760,7 @@
// later.
HeapRegion* hr = new_region(word_size, true /* is_old */, false /* do_expand */);
if (hr != NULL) {
- first = hr->hrs_index();
+ first = hr->hrm_index();
}
} else {
// We can't allocate humongous regions spanning more than one region while
@@ -776,18 +776,18 @@
// Policy: Try only empty regions (i.e. already committed first). Maybe we
// are lucky enough to find some.
- first = _hrs.find_contiguous_only_empty(obj_regions);
- if (first != G1_NO_HRS_INDEX) {
- _hrs.allocate_free_regions_starting_at(first, obj_regions);
- }
- }
-
- if (first == G1_NO_HRS_INDEX) {
+ first = _hrm.find_contiguous_only_empty(obj_regions);
+ if (first != G1_NO_HRM_INDEX) {
+ _hrm.allocate_free_regions_starting_at(first, obj_regions);
+ }
+ }
+
+ if (first == G1_NO_HRM_INDEX) {
// Policy: We could not find enough regions for the humongous object in the
// free list. Look through the heap to find a mix of free and uncommitted regions.
// If so, try expansion.
- first = _hrs.find_contiguous_empty_or_unavailable(obj_regions);
- if (first != G1_NO_HRS_INDEX) {
+ first = _hrm.find_contiguous_empty_or_unavailable(obj_regions);
+ if (first != G1_NO_HRM_INDEX) {
// We found something. Make sure these regions are committed, i.e. expand
// the heap. Alternatively we could do a defragmentation GC.
ergo_verbose1(ErgoHeapSizing,
@@ -796,7 +796,7 @@
ergo_format_byte("allocation request"),
word_size * HeapWordSize);
- _hrs.expand_at(first, obj_regions);
+ _hrm.expand_at(first, obj_regions);
g1_policy()->record_new_heap_size(num_regions());
#ifdef ASSERT
@@ -806,14 +806,14 @@
assert(is_on_master_free_list(hr), "sanity");
}
#endif
- _hrs.allocate_free_regions_starting_at(first, obj_regions);
+ _hrm.allocate_free_regions_starting_at(first, obj_regions);
} else {
// Policy: Potentially trigger a defragmentation GC.
}
}
HeapWord* result = NULL;
- if (first != G1_NO_HRS_INDEX) {
+ if (first != G1_NO_HRM_INDEX) {
result = humongous_obj_allocate_initialize_regions(first, obj_regions, word_size);
assert(result != NULL, "it should always return a valid result");
@@ -1248,7 +1248,7 @@
: _hr_printer(hr_printer) { }
};
-void G1CollectedHeap::print_hrs_post_compaction() {
+void G1CollectedHeap::print_hrm_post_compaction() {
PostCompactionPrinterClosure cl(hr_printer());
heap_region_iterate(&cl);
}
@@ -1417,7 +1417,7 @@
// that all the COMMIT / UNCOMMIT events are generated before
// the end GC event.
- print_hrs_post_compaction();
+ print_hrm_post_compaction();
_hr_printer.end_gc(true /* full */, (size_t) total_collections());
}
@@ -1490,7 +1490,7 @@
// Update the number of full collections that have been completed.
increment_old_marking_cycles_completed(false /* concurrent */);
- _hrs.verify_optional();
+ _hrm.verify_optional();
verify_region_sets_optional();
verify_after_gc();
@@ -1734,7 +1734,7 @@
ergo_format_byte("allocation request"),
word_size * HeapWordSize);
if (expand(expand_bytes)) {
- _hrs.verify_optional();
+ _hrm.verify_optional();
verify_region_sets_optional();
return attempt_allocation_at_safepoint(word_size,
false /* expect_null_mutator_alloc_region */);
@@ -1762,7 +1762,7 @@
uint regions_to_expand = (uint)(aligned_expand_bytes / HeapRegion::GrainBytes);
assert(regions_to_expand > 0, "Must expand by at least one region");
- uint expanded_by = _hrs.expand_by(regions_to_expand);
+ uint expanded_by = _hrm.expand_by(regions_to_expand);
if (expanded_by > 0) {
size_t actual_expand_bytes = expanded_by * HeapRegion::GrainBytes;
@@ -1775,7 +1775,7 @@
// The expansion of the virtual storage space was unsuccessful.
// Let's see if it was because we ran out of swap.
if (G1ExitOnExpansionFailure &&
- _hrs.available() >= regions_to_expand) {
+ _hrm.available() >= regions_to_expand) {
// We had head room...
vm_exit_out_of_memory(aligned_expand_bytes, OOM_MMAP_ERROR, "G1 heap expansion");
}
@@ -1790,7 +1790,7 @@
HeapRegion::GrainBytes);
uint num_regions_to_remove = (uint)(shrink_bytes / HeapRegion::GrainBytes);
- uint num_regions_removed = _hrs.shrink_by(num_regions_to_remove);
+ uint num_regions_removed = _hrm.shrink_by(num_regions_to_remove);
size_t shrunk_bytes = num_regions_removed * HeapRegion::GrainBytes;
ergo_verbose3(ErgoHeapSizing,
@@ -1823,7 +1823,7 @@
shrink_helper(shrink_bytes);
rebuild_region_sets(true /* free_list_only */);
- _hrs.verify_optional();
+ _hrm.verify_optional();
verify_region_sets_optional();
}
@@ -1867,6 +1867,7 @@
_old_marking_cycles_started(0),
_old_marking_cycles_completed(0),
_concurrent_cycle_started(false),
+ _heap_summary_sent(false),
_in_cset_fast_test(),
_dirty_cards_region_list(NULL),
_worker_cset_start_region(NULL),
@@ -2032,7 +2033,7 @@
CMBitMap::mark_distance(),
mtGC);
- _hrs.initialize(heap_storage, prev_bitmap_storage, next_bitmap_storage, bot_storage, cardtable_storage, card_counts_storage);
+ _hrm.initialize(heap_storage, prev_bitmap_storage, next_bitmap_storage, bot_storage, cardtable_storage, card_counts_storage);
g1_barrier_set()->initialize(cardtable_storage);
// Do later initialization work for concurrent refinement.
_cg1r->init(card_counts_storage);
@@ -2053,8 +2054,8 @@
_g1h = this;
- _in_cset_fast_test.initialize(_hrs.reserved().start(), _hrs.reserved().end(), HeapRegion::GrainBytes);
- _humongous_is_live.initialize(_hrs.reserved().start(), _hrs.reserved().end(), HeapRegion::GrainBytes);
+ _in_cset_fast_test.initialize(_hrm.reserved().start(), _hrm.reserved().end(), HeapRegion::GrainBytes);
+ _humongous_is_live.initialize(_hrm.reserved().start(), _hrm.reserved().end(), HeapRegion::GrainBytes);
// Create the ConcurrentMark data structure and thread.
// (Must do this late, so that "max_regions" is defined.)
@@ -2115,7 +2116,7 @@
// Here we allocate the dummy HeapRegion that is required by the
// G1AllocRegion class.
- HeapRegion* dummy_region = _hrs.get_dummy_region();
+ HeapRegion* dummy_region = _hrm.get_dummy_region();
// We'll re-use the same region whether the alloc region will
// require BOT updates or not and, if it doesn't, then a non-young
@@ -2232,14 +2233,14 @@
}
size_t G1CollectedHeap::capacity() const {
- return _hrs.length() * HeapRegion::GrainBytes;
+ return _hrm.length() * HeapRegion::GrainBytes;
}
void G1CollectedHeap::reset_gc_time_stamps(HeapRegion* hr) {
assert(!hr->continuesHumongous(), "pre-condition");
hr->reset_gc_time_stamp();
if (hr->startsHumongous()) {
- uint first_index = hr->hrs_index() + 1;
+ uint first_index = hr->hrm_index() + 1;
uint last_index = hr->last_hc_index();
for (uint i = first_index; i < last_index; i += 1) {
HeapRegion* chr = region_at(i);
@@ -2445,13 +2446,24 @@
_gc_timer_cm->register_gc_end();
_gc_tracer_cm->report_gc_end(_gc_timer_cm->gc_end(), _gc_timer_cm->time_partitions());
+ // Clear state variables to prepare for the next concurrent cycle.
_concurrent_cycle_started = false;
+ _heap_summary_sent = false;
}
}
void G1CollectedHeap::trace_heap_after_concurrent_cycle() {
if (_concurrent_cycle_started) {
- trace_heap_after_gc(_gc_tracer_cm);
+ // This function can be called when:
+ // the cleanup pause is run
+ // the concurrent cycle is aborted before the cleanup pause.
+ // the concurrent cycle is aborted after the cleanup pause,
+ // but before the concurrent cycle end has been registered.
+ // Make sure that we only send the heap information once.
+ if (!_heap_summary_sent) {
+ trace_heap_after_gc(_gc_tracer_cm);
+ _heap_summary_sent = true;
+ }
}
}
@@ -2537,7 +2549,7 @@
}
bool G1CollectedHeap::is_in(const void* p) const {
- if (_hrs.reserved().contains(p)) {
+ if (_hrm.reserved().contains(p)) {
// Given that we know that p is in the reserved space,
// heap_region_containing_raw() should successfully
// return the containing region.
@@ -2551,7 +2563,7 @@
#ifdef ASSERT
bool G1CollectedHeap::is_in_exact(const void* p) const {
bool contains = reserved_region().contains(p);
- bool available = _hrs.is_available(addr_to_region((HeapWord*)p));
+ bool available = _hrm.is_available(addr_to_region((HeapWord*)p));
if (contains && available) {
return true;
} else {
@@ -2618,7 +2630,7 @@
}
void G1CollectedHeap::heap_region_iterate(HeapRegionClosure* cl) const {
- _hrs.iterate(cl);
+ _hrm.iterate(cl);
}
void
@@ -2626,7 +2638,7 @@
uint worker_id,
uint num_workers,
jint claim_value) const {
- _hrs.par_iterate(cl, worker_id, num_workers, claim_value);
+ _hrm.par_iterate(cl, worker_id, num_workers, claim_value);
}
class ResetClaimValuesClosure: public HeapRegionClosure {
@@ -2846,9 +2858,9 @@
}
HeapRegion* G1CollectedHeap::next_compaction_region(const HeapRegion* from) const {
- HeapRegion* result = _hrs.next_region_in_heap(from);
+ HeapRegion* result = _hrm.next_region_in_heap(from);
while (result != NULL && result->isHumongous()) {
- result = _hrs.next_region_in_heap(result);
+ result = _hrm.next_region_in_heap(result);
}
return result;
}
@@ -2908,7 +2920,7 @@
}
size_t G1CollectedHeap::max_capacity() const {
- return _hrs.reserved().byte_size();
+ return _hrm.reserved().byte_size();
}
jlong G1CollectedHeap::millis_since_last_gc() {
@@ -3437,9 +3449,9 @@
st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K",
capacity()/K, used_unlocked()/K);
st->print(" [" INTPTR_FORMAT ", " INTPTR_FORMAT ", " INTPTR_FORMAT ")",
- _hrs.reserved().start(),
- _hrs.reserved().start() + _hrs.length() + HeapRegion::GrainWords,
- _hrs.reserved().end());
+ _hrm.reserved().start(),
+ _hrm.reserved().start() + _hrm.length() + HeapRegion::GrainWords,
+ _hrm.reserved().end());
st->cr();
st->print(" region size " SIZE_FORMAT "K, ", HeapRegion::GrainBytes / K);
uint young_regions = _young_list->length();
@@ -3682,7 +3694,7 @@
}
G1CollectedHeap* g1h = G1CollectedHeap::heap();
- uint region_idx = r->hrs_index();
+ uint region_idx = r->hrm_index();
bool is_candidate = !g1h->humongous_region_is_always_live(region_idx);
// Is_candidate already filters out humongous regions with some remembered set.
// This will not lead to humongous object that we mistakenly keep alive because
@@ -4205,7 +4217,7 @@
// output from the concurrent mark thread interfering with this
// logging output either.
- _hrs.verify_optional();
+ _hrm.verify_optional();
verify_region_sets_optional();
TASKQUEUE_STATS_ONLY(if (ParallelGCVerbose) print_taskqueue_stats());
@@ -6024,7 +6036,7 @@
bool locked) {
assert(!hr->isHumongous(), "this is only for non-humongous regions");
assert(!hr->is_empty(), "the region should not be empty");
- assert(_hrs.is_available(hr->hrs_index()), "region should be committed");
+ assert(_hrm.is_available(hr->hrm_index()), "region should be committed");
assert(free_list != NULL, "pre-condition");
if (G1VerifyBitmaps) {
@@ -6055,7 +6067,7 @@
hr->set_notHumongous();
free_region(hr, free_list, par);
- uint i = hr->hrs_index() + 1;
+ uint i = hr->hrm_index() + 1;
while (i < last_index) {
HeapRegion* curr_hr = region_at(i);
assert(curr_hr->continuesHumongous(), "invariant");
@@ -6079,7 +6091,7 @@
assert(list != NULL, "list can't be null");
if (!list->is_empty()) {
MutexLockerEx x(FreeList_lock, Mutex::_no_safepoint_check_flag);
- _hrs.insert_list_into_free_list(list);
+ _hrm.insert_list_into_free_list(list);
}
}
@@ -6448,7 +6460,7 @@
// While this cleanup is not strictly necessary to be done (or done instantly),
// given that their occurrence is very low, this saves us this additional
// complexity.
- uint region_idx = r->hrs_index();
+ uint region_idx = r->hrm_index();
if (g1h->humongous_is_live(region_idx) ||
g1h->humongous_region_is_always_live(region_idx)) {
@@ -6687,22 +6699,22 @@
// this is that during a full GC string deduplication needs to know if
// a collected region was young or old when the full GC was initiated.
}
- _hrs.remove_all_free_regions();
+ _hrm.remove_all_free_regions();
}
class RebuildRegionSetsClosure : public HeapRegionClosure {
private:
bool _free_list_only;
HeapRegionSet* _old_set;
- HeapRegionSeq* _hrs;
+ HeapRegionManager* _hrm;
size_t _total_used;
public:
RebuildRegionSetsClosure(bool free_list_only,
- HeapRegionSet* old_set, HeapRegionSeq* hrs) :
+ HeapRegionSet* old_set, HeapRegionManager* hrm) :
_free_list_only(free_list_only),
- _old_set(old_set), _hrs(hrs), _total_used(0) {
- assert(_hrs->num_free_regions() == 0, "pre-condition");
+ _old_set(old_set), _hrm(hrm), _total_used(0) {
+ assert(_hrm->num_free_regions() == 0, "pre-condition");
if (!free_list_only) {
assert(_old_set->is_empty(), "pre-condition");
}
@@ -6715,7 +6727,7 @@
if (r->is_empty()) {
// Add free regions to the free list
- _hrs->insert_into_free_list(r);
+ _hrm->insert_into_free_list(r);
} else if (!_free_list_only) {
assert(!r->is_young(), "we should not come across young regions");
@@ -6743,7 +6755,7 @@
_young_list->empty_list();
}
- RebuildRegionSetsClosure cl(free_list_only, &_old_set, &_hrs);
+ RebuildRegionSetsClosure cl(free_list_only, &_old_set, &_hrm);
heap_region_iterate(&cl);
if (!free_list_only) {
@@ -6933,7 +6945,7 @@
private:
HeapRegionSet* _old_set;
HeapRegionSet* _humongous_set;
- HeapRegionSeq* _hrs;
+ HeapRegionManager* _hrm;
public:
HeapRegionSetCount _old_count;
@@ -6942,8 +6954,8 @@
VerifyRegionListsClosure(HeapRegionSet* old_set,
HeapRegionSet* humongous_set,
- HeapRegionSeq* hrs) :
- _old_set(old_set), _humongous_set(humongous_set), _hrs(hrs),
+ HeapRegionManager* hrm) :
+ _old_set(old_set), _humongous_set(humongous_set), _hrm(hrm),
_old_count(), _humongous_count(), _free_count(){ }
bool doHeapRegion(HeapRegion* hr) {
@@ -6954,19 +6966,19 @@
if (hr->is_young()) {
// TODO
} else if (hr->startsHumongous()) {
- assert(hr->containing_set() == _humongous_set, err_msg("Heap region %u is starts humongous but not in humongous set.", hr->hrs_index()));
+ assert(hr->containing_set() == _humongous_set, err_msg("Heap region %u is starts humongous but not in humongous set.", hr->hrm_index()));
_humongous_count.increment(1u, hr->capacity());
} else if (hr->is_empty()) {
- assert(_hrs->is_free(hr), err_msg("Heap region %u is empty but not on the free list.", hr->hrs_index()));
+ assert(_hrm->is_free(hr), err_msg("Heap region %u is empty but not on the free list.", hr->hrm_index()));
_free_count.increment(1u, hr->capacity());
} else {
- assert(hr->containing_set() == _old_set, err_msg("Heap region %u is old but not in the old set.", hr->hrs_index()));
+ assert(hr->containing_set() == _old_set, err_msg("Heap region %u is old but not in the old set.", hr->hrm_index()));
_old_count.increment(1u, hr->capacity());
}
return false;
}
- void verify_counts(HeapRegionSet* old_set, HeapRegionSet* humongous_set, HeapRegionSeq* free_list) {
+ void verify_counts(HeapRegionSet* old_set, HeapRegionSet* humongous_set, HeapRegionManager* free_list) {
guarantee(old_set->length() == _old_count.length(), err_msg("Old set count mismatch. Expected %u, actual %u.", old_set->length(), _old_count.length()));
guarantee(old_set->total_capacity_bytes() == _old_count.capacity(), err_msg("Old set capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT,
old_set->total_capacity_bytes(), _old_count.capacity()));
@@ -6985,7 +6997,7 @@
assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */);
// First, check the explicit lists.
- _hrs.verify();
+ _hrm.verify();
{
// Given that a concurrent operation might be adding regions to
// the secondary free list we have to take the lock before
@@ -7016,9 +7028,9 @@
// Finally, make sure that the region accounting in the lists is
// consistent with what we see in the heap.
- VerifyRegionListsClosure cl(&_old_set, &_humongous_set, &_hrs);
+ VerifyRegionListsClosure cl(&_old_set, &_humongous_set, &_hrm);
heap_region_iterate(&cl);
- cl.verify_counts(&_old_set, &_humongous_set, &_hrs);
+ cl.verify_counts(&_old_set, &_humongous_set, &_hrm);
}
// Optimized nmethod scanning
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -33,7 +33,7 @@
#include "gc_implementation/g1/g1MonitoringSupport.hpp"
#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
#include "gc_implementation/g1/g1YCTypes.hpp"
-#include "gc_implementation/g1/heapRegionSeq.hpp"
+#include "gc_implementation/g1/heapRegionManager.hpp"
#include "gc_implementation/g1/heapRegionSet.hpp"
#include "gc_implementation/shared/hSpaceCounters.hpp"
#include "gc_implementation/shared/parGCAllocBuffer.hpp"
@@ -291,7 +291,7 @@
G1RegionMappingChangedListener _listener;
// The sequence of all heap regions in the heap.
- HeapRegionSeq _hrs;
+ HeapRegionManager _hrm;
// Alloc region used to satisfy mutator allocation requests.
MutatorAllocRegion _mutator_alloc_region;
@@ -415,6 +415,7 @@
volatile unsigned int _old_marking_cycles_completed;
bool _concurrent_cycle_started;
+ bool _heap_summary_sent;
// This is a non-product method that is helpful for testing. It is
// called at the end of a GC and artificially expands the heap by
@@ -429,7 +430,7 @@
// If the HR printer is active, dump the state of the regions in the
// heap after a compaction.
- void print_hrs_post_compaction();
+ void print_hrm_post_compaction();
double verify(bool guard, const char* msg);
void verify_before_gc();
@@ -715,7 +716,7 @@
// We register a region with the fast "in collection set" test. We
// simply set to true the array slot corresponding to this region.
void register_region_with_in_cset_fast_test(HeapRegion* r) {
- _in_cset_fast_test.set_in_cset(r->hrs_index());
+ _in_cset_fast_test.set_in_cset(r->hrm_index());
}
// This is a fast test on whether a reference points into the
@@ -1171,17 +1172,17 @@
// But G1CollectedHeap doesn't yet support this.
virtual bool is_maximal_no_gc() const {
- return _hrs.available() == 0;
+ return _hrm.available() == 0;
}
// The current number of regions in the heap.
- uint num_regions() const { return _hrs.length(); }
+ uint num_regions() const { return _hrm.length(); }
// The max number of regions in the heap.
- uint max_regions() const { return _hrs.max_length(); }
+ uint max_regions() const { return _hrm.max_length(); }
// The number of regions that are completely free.
- uint num_free_regions() const { return _hrs.num_free_regions(); }
+ uint num_free_regions() const { return _hrm.num_free_regions(); }
// The number of regions that are not completely free.
uint num_used_regions() const { return num_regions() - num_free_regions(); }
@@ -1233,7 +1234,7 @@
#ifdef ASSERT
bool is_on_master_free_list(HeapRegion* hr) {
- return _hrs.is_free(hr);
+ return _hrm.is_free(hr);
}
#endif // ASSERT
@@ -1245,7 +1246,7 @@
}
void append_secondary_free_list() {
- _hrs.insert_list_into_free_list(&_secondary_free_list);
+ _hrm.insert_list_into_free_list(&_secondary_free_list);
}
void append_secondary_free_list_if_not_empty_with_lock() {
@@ -1356,13 +1357,13 @@
// Return "TRUE" iff the given object address is in the reserved
// region of g1.
bool is_in_g1_reserved(const void* p) const {
- return _hrs.reserved().contains(p);
+ return _hrm.reserved().contains(p);
}
// Returns a MemRegion that corresponds to the space that has been
// reserved for the heap
MemRegion g1_reserved() const {
- return _hrs.reserved();
+ return _hrm.reserved();
}
virtual bool is_in_closed_subset(const void* p) const;
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -30,15 +30,15 @@
#include "gc_implementation/g1/g1AllocRegion.inline.hpp"
#include "gc_implementation/g1/g1CollectorPolicy.hpp"
#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
#include "gc_implementation/g1/heapRegionSet.inline.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
#include "runtime/orderAccess.inline.hpp"
#include "utilities/taskqueue.hpp"
// Inline functions for G1CollectedHeap
// Return the region with the given index. It assumes the index is valid.
-inline HeapRegion* G1CollectedHeap::region_at(uint index) const { return _hrs.at(index); }
+inline HeapRegion* G1CollectedHeap::region_at(uint index) const { return _hrm.at(index); }
inline uint G1CollectedHeap::addr_to_region(HeapWord* addr) const {
assert(is_in_reserved(addr),
@@ -48,7 +48,7 @@
}
inline HeapWord* G1CollectedHeap::bottom_addr_for_region(uint index) const {
- return _hrs.reserved().start() + index * HeapRegion::GrainWords;
+ return _hrm.reserved().start() + index * HeapRegion::GrainWords;
}
template <class T>
@@ -57,7 +57,7 @@
assert(is_in_g1_reserved((const void*) addr),
err_msg("Address "PTR_FORMAT" is outside of the heap ranging from ["PTR_FORMAT" to "PTR_FORMAT")",
p2i((void*)addr), p2i(g1_reserved().start()), p2i(g1_reserved().end())));
- return _hrs.addr_to_region((HeapWord*) addr);
+ return _hrm.addr_to_region((HeapWord*) addr);
}
template <class T>
@@ -87,7 +87,7 @@
}
inline bool G1CollectedHeap::obj_in_cs(oop obj) {
- HeapRegion* r = _hrs.addr_to_region((HeapWord*) obj);
+ HeapRegion* r = _hrm.addr_to_region((HeapWord*) obj);
return r != NULL && r->in_collection_set();
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -32,7 +32,7 @@
#include "gc_implementation/g1/g1GCPhaseTimes.hpp"
#include "gc_implementation/g1/g1OopClosures.inline.hpp"
#include "gc_implementation/g1/g1RemSet.inline.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
#include "gc_implementation/g1/heapRegionRemSet.hpp"
#include "memory/iterator.hpp"
#include "oops/oop.inline.hpp"
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -29,7 +29,7 @@
#include "gc_implementation/g1/g1OopClosures.inline.hpp"
#include "gc_implementation/g1/heapRegion.inline.hpp"
#include "gc_implementation/g1/heapRegionRemSet.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
#include "gc_implementation/shared/liveRange.hpp"
#include "memory/genOopClosures.inline.hpp"
#include "memory/iterator.hpp"
@@ -322,34 +322,11 @@
return false;
}
-HeapWord* HeapRegion::next_block_start_careful(HeapWord* addr) {
- HeapWord* low = addr;
- HeapWord* high = end();
- while (low < high) {
- size_t diff = pointer_delta(high, low);
- // Must add one below to bias toward the high amount. Otherwise, if
- // "high" were at the desired value, and "low" were one less, we
- // would not converge on "high". This is not symmetric, because
- // we set "high" to a block start, which might be the right one,
- // which we don't do for "low".
- HeapWord* middle = low + (diff+1)/2;
- if (middle == high) return high;
- HeapWord* mid_bs = block_start_careful(middle);
- if (mid_bs < addr) {
- low = middle;
- } else {
- high = mid_bs;
- }
- }
- assert(low == high && low >= addr, "Didn't work.");
- return low;
-}
-
-HeapRegion::HeapRegion(uint hrs_index,
+HeapRegion::HeapRegion(uint hrm_index,
G1BlockOffsetSharedArray* sharedOffsetArray,
MemRegion mr) :
G1OffsetTableContigSpace(sharedOffsetArray, mr),
- _hrs_index(hrs_index),
+ _hrm_index(hrm_index),
_humongous_type(NotHumongous), _humongous_start_region(NULL),
_in_collection_set(false),
_next_in_special_set(NULL), _orig_end(NULL),
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -54,15 +54,15 @@
#define HR_FORMAT "%u:(%s)["PTR_FORMAT","PTR_FORMAT","PTR_FORMAT"]"
#define HR_FORMAT_PARAMS(_hr_) \
- (_hr_)->hrs_index(), \
+ (_hr_)->hrm_index(), \
(_hr_)->is_survivor() ? "S" : (_hr_)->is_young() ? "E" : \
(_hr_)->startsHumongous() ? "HS" : \
(_hr_)->continuesHumongous() ? "HC" : \
!(_hr_)->is_empty() ? "O" : "F", \
p2i((_hr_)->bottom()), p2i((_hr_)->top()), p2i((_hr_)->end())
-// sentinel value for hrs_index
-#define G1_NO_HRS_INDEX ((uint) -1)
+// sentinel value for hrm_index
+#define G1_NO_HRM_INDEX ((uint) -1)
// A dirty card to oop closure for heap regions. It
// knows how to get the G1 heap and how to use the bitmap
@@ -206,10 +206,6 @@
_offsets.reset_bot();
}
- void update_bot_for_object(HeapWord* start, size_t word_size) {
- _offsets.alloc_block(start, word_size);
- }
-
void print_bot_on(outputStream* out) {
_offsets.print_on(out);
}
@@ -234,7 +230,7 @@
protected:
// The index of this region in the heap region sequence.
- uint _hrs_index;
+ uint _hrm_index;
HumongousType _humongous_type;
// For a humongous region, region in which it starts.
@@ -330,7 +326,7 @@
size_t _predicted_bytes_to_copy;
public:
- HeapRegion(uint hrs_index,
+ HeapRegion(uint hrm_index,
G1BlockOffsetSharedArray* sharedOffsetArray,
MemRegion mr);
@@ -385,9 +381,9 @@
inline HeapWord* par_allocate_no_bot_updates(size_t word_size);
inline HeapWord* allocate_no_bot_updates(size_t word_size);
- // If this region is a member of a HeapRegionSeq, the index in that
+ // If this region is a member of a HeapRegionManager, the index in that
// sequence, otherwise -1.
- uint hrs_index() const { return _hrs_index; }
+ uint hrm_index() const { return _hrm_index; }
// The number of bytes marked live in the region in the last marking phase.
size_t marked_bytes() { return _prev_marked_bytes; }
@@ -458,7 +454,7 @@
// with this HS region.
uint last_hc_index() const {
assert(startsHumongous(), "don't call this otherwise");
- return hrs_index() + region_num();
+ return hrm_index() + region_num();
}
// Same as Space::is_in_reserved, but will use the original size of the region.
@@ -570,7 +566,7 @@
void set_next_dirty_cards_region(HeapRegion* hr) { _next_dirty_cards_region = hr; }
bool is_on_dirty_cards_region_list() const { return get_next_dirty_cards_region() != NULL; }
- HeapWord* orig_end() { return _orig_end; }
+ HeapWord* orig_end() const { return _orig_end; }
// Reset HR stuff to default values.
void hr_clear(bool par, bool clear_space, bool locked = false);
@@ -737,18 +733,6 @@
bool filter_young,
jbyte* card_ptr);
- // A version of block start that is guaranteed to find *some* block
- // boundary at or before "p", but does not object iteration, and may
- // therefore be used safely when the heap is unparseable.
- HeapWord* block_start_careful(const void* p) const {
- return _offsets.block_start_careful(p);
- }
-
- // Requires that "addr" is within the region. Returns the start of the
- // first ("careful") block that starts at or after "addr", or else the
- // "end" of the region if there is no such block.
- HeapWord* next_block_start_careful(HeapWord* addr);
-
size_t recorded_rs_length() const { return _recorded_rs_length; }
double predicted_elapsed_time_ms() const { return _predicted_elapsed_time_ms; }
size_t predicted_bytes_to_copy() const { return _predicted_bytes_to_copy; }
@@ -813,7 +797,7 @@
// HeapRegionClosure is used for iterating over regions.
// Terminates the iteration when the "doHeapRegion" method returns "true".
class HeapRegionClosure : public StackObj {
- friend class HeapRegionSeq;
+ friend class HeapRegionManager;
friend class G1CollectedHeap;
bool _complete;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2001, 2014, 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 "gc_implementation/g1/heapRegion.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
+#include "gc_implementation/g1/heapRegionSet.inline.hpp"
+#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
+#include "gc_implementation/g1/concurrentG1Refine.hpp"
+#include "memory/allocation.hpp"
+
+void HeapRegionManager::initialize(G1RegionToSpaceMapper* heap_storage,
+ G1RegionToSpaceMapper* prev_bitmap,
+ G1RegionToSpaceMapper* next_bitmap,
+ G1RegionToSpaceMapper* bot,
+ G1RegionToSpaceMapper* cardtable,
+ G1RegionToSpaceMapper* card_counts) {
+ _allocated_heapregions_length = 0;
+
+ _heap_mapper = heap_storage;
+
+ _prev_bitmap_mapper = prev_bitmap;
+ _next_bitmap_mapper = next_bitmap;
+
+ _bot_mapper = bot;
+ _cardtable_mapper = cardtable;
+
+ _card_counts_mapper = card_counts;
+
+ MemRegion reserved = heap_storage->reserved();
+ _regions.initialize(reserved.start(), reserved.end(), HeapRegion::GrainBytes);
+
+ _available_map.resize(_regions.length(), false);
+ _available_map.clear();
+}
+
+bool HeapRegionManager::is_available(uint region) const {
+ return _available_map.at(region);
+}
+
+#ifdef ASSERT
+bool HeapRegionManager::is_free(HeapRegion* hr) const {
+ return _free_list.contains(hr);
+}
+#endif
+
+HeapRegion* HeapRegionManager::new_heap_region(uint hrm_index) {
+ HeapWord* bottom = G1CollectedHeap::heap()->bottom_addr_for_region(hrm_index);
+ MemRegion mr(bottom, bottom + HeapRegion::GrainWords);
+ assert(reserved().contains(mr), "invariant");
+ return new HeapRegion(hrm_index, G1CollectedHeap::heap()->bot_shared(), mr);
+}
+
+void HeapRegionManager::commit_regions(uint index, size_t num_regions) {
+ guarantee(num_regions > 0, "Must commit more than zero regions");
+ guarantee(_num_committed + num_regions <= max_length(), "Cannot commit more than the maximum amount of regions");
+
+ _num_committed += (uint)num_regions;
+
+ _heap_mapper->commit_regions(index, num_regions);
+
+ // Also commit auxiliary data
+ _prev_bitmap_mapper->commit_regions(index, num_regions);
+ _next_bitmap_mapper->commit_regions(index, num_regions);
+
+ _bot_mapper->commit_regions(index, num_regions);
+ _cardtable_mapper->commit_regions(index, num_regions);
+
+ _card_counts_mapper->commit_regions(index, num_regions);
+}
+
+void HeapRegionManager::uncommit_regions(uint start, size_t num_regions) {
+ guarantee(num_regions >= 1, err_msg("Need to specify at least one region to uncommit, tried to uncommit zero regions at %u", start));
+ guarantee(_num_committed >= num_regions, "pre-condition");
+
+ // Print before uncommitting.
+ if (G1CollectedHeap::heap()->hr_printer()->is_active()) {
+ for (uint i = start; i < start + num_regions; i++) {
+ HeapRegion* hr = at(i);
+ G1CollectedHeap::heap()->hr_printer()->uncommit(hr->bottom(), hr->end());
+ }
+ }
+
+ _num_committed -= (uint)num_regions;
+
+ _available_map.par_clear_range(start, start + num_regions, BitMap::unknown_range);
+ _heap_mapper->uncommit_regions(start, num_regions);
+
+ // Also uncommit auxiliary data
+ _prev_bitmap_mapper->uncommit_regions(start, num_regions);
+ _next_bitmap_mapper->uncommit_regions(start, num_regions);
+
+ _bot_mapper->uncommit_regions(start, num_regions);
+ _cardtable_mapper->uncommit_regions(start, num_regions);
+
+ _card_counts_mapper->uncommit_regions(start, num_regions);
+}
+
+void HeapRegionManager::make_regions_available(uint start, uint num_regions) {
+ guarantee(num_regions > 0, "No point in calling this for zero regions");
+ commit_regions(start, num_regions);
+ for (uint i = start; i < start + num_regions; i++) {
+ if (_regions.get_by_index(i) == NULL) {
+ HeapRegion* new_hr = new_heap_region(i);
+ _regions.set_by_index(i, new_hr);
+ _allocated_heapregions_length = MAX2(_allocated_heapregions_length, i + 1);
+ }
+ }
+
+ _available_map.par_set_range(start, start + num_regions, BitMap::unknown_range);
+
+ for (uint i = start; i < start + num_regions; i++) {
+ assert(is_available(i), err_msg("Just made region %u available but is apparently not.", i));
+ HeapRegion* hr = at(i);
+ if (G1CollectedHeap::heap()->hr_printer()->is_active()) {
+ G1CollectedHeap::heap()->hr_printer()->commit(hr->bottom(), hr->end());
+ }
+ HeapWord* bottom = G1CollectedHeap::heap()->bottom_addr_for_region(i);
+ MemRegion mr(bottom, bottom + HeapRegion::GrainWords);
+
+ hr->initialize(mr);
+ insert_into_free_list(at(i));
+ }
+}
+
+uint HeapRegionManager::expand_by(uint num_regions) {
+ return expand_at(0, num_regions);
+}
+
+uint HeapRegionManager::expand_at(uint start, uint num_regions) {
+ if (num_regions == 0) {
+ return 0;
+ }
+
+ uint cur = start;
+ uint idx_last_found = 0;
+ uint num_last_found = 0;
+
+ uint expanded = 0;
+
+ while (expanded < num_regions &&
+ (num_last_found = find_unavailable_from_idx(cur, &idx_last_found)) > 0) {
+ uint to_expand = MIN2(num_regions - expanded, num_last_found);
+ make_regions_available(idx_last_found, to_expand);
+ expanded += to_expand;
+ cur = idx_last_found + num_last_found + 1;
+ }
+
+ verify_optional();
+ return expanded;
+}
+
+uint HeapRegionManager::find_contiguous(size_t num, bool empty_only) {
+ uint found = 0;
+ size_t length_found = 0;
+ uint cur = 0;
+
+ while (length_found < num && cur < max_length()) {
+ HeapRegion* hr = _regions.get_by_index(cur);
+ if ((!empty_only && !is_available(cur)) || (is_available(cur) && hr != NULL && hr->is_empty())) {
+ // This region is a potential candidate for allocation into.
+ length_found++;
+ } else {
+ // This region is not a candidate. The next region is the next possible one.
+ found = cur + 1;
+ length_found = 0;
+ }
+ cur++;
+ }
+
+ if (length_found == num) {
+ for (uint i = found; i < (found + num); i++) {
+ HeapRegion* hr = _regions.get_by_index(i);
+ // sanity check
+ guarantee((!empty_only && !is_available(i)) || (is_available(i) && hr != NULL && hr->is_empty()),
+ err_msg("Found region sequence starting at " UINT32_FORMAT ", length " SIZE_FORMAT
+ " that is not empty at " UINT32_FORMAT ". Hr is " PTR_FORMAT, found, num, i, p2i(hr)));
+ }
+ return found;
+ } else {
+ return G1_NO_HRM_INDEX;
+ }
+}
+
+HeapRegion* HeapRegionManager::next_region_in_heap(const HeapRegion* r) const {
+ guarantee(r != NULL, "Start region must be a valid region");
+ guarantee(is_available(r->hrm_index()), err_msg("Trying to iterate starting from region %u which is not in the heap", r->hrm_index()));
+ for (uint i = r->hrm_index() + 1; i < _allocated_heapregions_length; i++) {
+ HeapRegion* hr = _regions.get_by_index(i);
+ if (is_available(i)) {
+ return hr;
+ }
+ }
+ return NULL;
+}
+
+void HeapRegionManager::iterate(HeapRegionClosure* blk) const {
+ uint len = max_length();
+
+ for (uint i = 0; i < len; i++) {
+ if (!is_available(i)) {
+ continue;
+ }
+ guarantee(at(i) != NULL, err_msg("Tried to access region %u that has a NULL HeapRegion*", i));
+ bool res = blk->doHeapRegion(at(i));
+ if (res) {
+ blk->incomplete();
+ return;
+ }
+ }
+}
+
+uint HeapRegionManager::find_unavailable_from_idx(uint start_idx, uint* res_idx) const {
+ guarantee(res_idx != NULL, "checking");
+ guarantee(start_idx <= (max_length() + 1), "checking");
+
+ uint num_regions = 0;
+
+ uint cur = start_idx;
+ while (cur < max_length() && is_available(cur)) {
+ cur++;
+ }
+ if (cur == max_length()) {
+ return num_regions;
+ }
+ *res_idx = cur;
+ while (cur < max_length() && !is_available(cur)) {
+ cur++;
+ }
+ num_regions = cur - *res_idx;
+#ifdef ASSERT
+ for (uint i = *res_idx; i < (*res_idx + num_regions); i++) {
+ assert(!is_available(i), "just checking");
+ }
+ assert(cur == max_length() || num_regions == 0 || is_available(cur),
+ err_msg("The region at the current position %u must be available or at the end of the heap.", cur));
+#endif
+ return num_regions;
+}
+
+uint HeapRegionManager::start_region_for_worker(uint worker_i, uint num_workers, uint num_regions) const {
+ return num_regions * worker_i / num_workers;
+}
+
+void HeapRegionManager::par_iterate(HeapRegionClosure* blk, uint worker_id, uint num_workers, jint claim_value) const {
+ const uint start_index = start_region_for_worker(worker_id, num_workers, _allocated_heapregions_length);
+
+ // Every worker will actually look at all regions, skipping over regions that
+ // are currently not committed.
+ // This also (potentially) iterates over regions newly allocated during GC. This
+ // is no problem except for some extra work.
+ for (uint count = 0; count < _allocated_heapregions_length; count++) {
+ const uint index = (start_index + count) % _allocated_heapregions_length;
+ assert(0 <= index && index < _allocated_heapregions_length, "sanity");
+ // Skip over unavailable regions
+ if (!is_available(index)) {
+ continue;
+ }
+ HeapRegion* r = _regions.get_by_index(index);
+ // We'll ignore "continues humongous" regions (we'll process them
+ // when we come across their corresponding "start humongous"
+ // region) and regions already claimed.
+ if (r->claim_value() == claim_value || r->continuesHumongous()) {
+ continue;
+ }
+ // OK, try to claim it
+ if (!r->claimHeapRegion(claim_value)) {
+ continue;
+ }
+ // Success!
+ if (r->startsHumongous()) {
+ // If the region is "starts humongous" we'll iterate over its
+ // "continues humongous" first; in fact we'll do them
+ // first. The order is important. In one case, calling the
+ // closure on the "starts humongous" region might de-allocate
+ // and clear all its "continues humongous" regions and, as a
+ // result, we might end up processing them twice. So, we'll do
+ // them first (note: most closures will ignore them anyway) and
+ // then we'll do the "starts humongous" region.
+ for (uint ch_index = index + 1; ch_index < index + r->region_num(); ch_index++) {
+ HeapRegion* chr = _regions.get_by_index(ch_index);
+
+ assert(chr->continuesHumongous(), "Must be humongous region");
+ assert(chr->humongous_start_region() == r,
+ err_msg("Must work on humongous continuation of the original start region "
+ PTR_FORMAT ", but is " PTR_FORMAT, p2i(r), p2i(chr)));
+ assert(chr->claim_value() != claim_value,
+ "Must not have been claimed yet because claiming of humongous continuation first claims the start region");
+
+ bool claim_result = chr->claimHeapRegion(claim_value);
+ // We should always be able to claim it; no one else should
+ // be trying to claim this region.
+ guarantee(claim_result, "We should always be able to claim the continuesHumongous part of the humongous object");
+
+ bool res2 = blk->doHeapRegion(chr);
+ if (res2) {
+ return;
+ }
+
+ // Right now, this holds (i.e., no closure that actually
+ // does something with "continues humongous" regions
+ // clears them). We might have to weaken it in the future,
+ // but let's leave these two asserts here for extra safety.
+ assert(chr->continuesHumongous(), "should still be the case");
+ assert(chr->humongous_start_region() == r, "sanity");
+ }
+ }
+
+ bool res = blk->doHeapRegion(r);
+ if (res) {
+ return;
+ }
+ }
+}
+
+uint HeapRegionManager::shrink_by(uint num_regions_to_remove) {
+ assert(length() > 0, "the region sequence should not be empty");
+ assert(length() <= _allocated_heapregions_length, "invariant");
+ assert(_allocated_heapregions_length > 0, "we should have at least one region committed");
+ assert(num_regions_to_remove < length(), "We should never remove all regions");
+
+ if (num_regions_to_remove == 0) {
+ return 0;
+ }
+
+ uint removed = 0;
+ uint cur = _allocated_heapregions_length - 1;
+ uint idx_last_found = 0;
+ uint num_last_found = 0;
+
+ while ((removed < num_regions_to_remove) &&
+ (num_last_found = find_empty_from_idx_reverse(cur, &idx_last_found)) > 0) {
+ uint to_remove = MIN2(num_regions_to_remove - removed, num_last_found);
+
+ uncommit_regions(idx_last_found + num_last_found - to_remove, to_remove);
+
+ cur -= num_last_found;
+ removed += to_remove;
+ }
+
+ verify_optional();
+
+ return removed;
+}
+
+uint HeapRegionManager::find_empty_from_idx_reverse(uint start_idx, uint* res_idx) const {
+ guarantee(start_idx < _allocated_heapregions_length, "checking");
+ guarantee(res_idx != NULL, "checking");
+
+ uint num_regions_found = 0;
+
+ jlong cur = start_idx;
+ while (cur != -1 && !(is_available(cur) && at(cur)->is_empty())) {
+ cur--;
+ }
+ if (cur == -1) {
+ return num_regions_found;
+ }
+ jlong old_cur = cur;
+ // cur indexes the first empty region
+ while (cur != -1 && is_available(cur) && at(cur)->is_empty()) {
+ cur--;
+ }
+ *res_idx = cur + 1;
+ num_regions_found = old_cur - cur;
+
+#ifdef ASSERT
+ for (uint i = *res_idx; i < (*res_idx + num_regions_found); i++) {
+ assert(at(i)->is_empty(), "just checking");
+ }
+#endif
+ return num_regions_found;
+}
+
+void HeapRegionManager::verify() {
+ guarantee(length() <= _allocated_heapregions_length,
+ err_msg("invariant: _length: %u _allocated_length: %u",
+ length(), _allocated_heapregions_length));
+ guarantee(_allocated_heapregions_length <= max_length(),
+ err_msg("invariant: _allocated_length: %u _max_length: %u",
+ _allocated_heapregions_length, max_length()));
+
+ bool prev_committed = true;
+ uint num_committed = 0;
+ HeapWord* prev_end = heap_bottom();
+ for (uint i = 0; i < _allocated_heapregions_length; i++) {
+ if (!is_available(i)) {
+ prev_committed = false;
+ continue;
+ }
+ num_committed++;
+ HeapRegion* hr = _regions.get_by_index(i);
+ guarantee(hr != NULL, err_msg("invariant: i: %u", i));
+ guarantee(!prev_committed || hr->bottom() == prev_end,
+ err_msg("invariant i: %u "HR_FORMAT" prev_end: "PTR_FORMAT,
+ i, HR_FORMAT_PARAMS(hr), p2i(prev_end)));
+ guarantee(hr->hrm_index() == i,
+ err_msg("invariant: i: %u hrm_index(): %u", i, hr->hrm_index()));
+ // Asserts will fire if i is >= _length
+ HeapWord* addr = hr->bottom();
+ guarantee(addr_to_region(addr) == hr, "sanity");
+ // We cannot check whether the region is part of a particular set: at the time
+ // this method may be called, we have only completed allocation of the regions,
+ // but not put into a region set.
+ prev_committed = true;
+ if (hr->startsHumongous()) {
+ prev_end = hr->orig_end();
+ } else {
+ prev_end = hr->end();
+ }
+ }
+ for (uint i = _allocated_heapregions_length; i < max_length(); i++) {
+ guarantee(_regions.get_by_index(i) == NULL, err_msg("invariant i: %u", i));
+ }
+
+ guarantee(num_committed == _num_committed, err_msg("Found %u committed regions, but should be %u", num_committed, _num_committed));
+ _free_list.verify();
+}
+
+#ifndef PRODUCT
+void HeapRegionManager::verify_optional() {
+ verify();
+}
+#endif // PRODUCT
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2001, 2013, 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_IMPLEMENTATION_G1_HEAPREGIONMANAGER_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONMANAGER_HPP
+
+#include "gc_implementation/g1/g1BiasedArray.hpp"
+#include "gc_implementation/g1/g1RegionToSpaceMapper.hpp"
+#include "gc_implementation/g1/heapRegionSet.hpp"
+
+class HeapRegion;
+class HeapRegionClosure;
+class FreeRegionList;
+
+class G1HeapRegionTable : public G1BiasedMappedArray<HeapRegion*> {
+ protected:
+ virtual HeapRegion* default_value() const { return NULL; }
+};
+
+// This class keeps track of the actual heap memory, auxiliary data
+// and its metadata (i.e., HeapRegion instances) and the list of free regions.
+//
+// This allows maximum flexibility for deciding what to commit or uncommit given
+// a request from outside.
+//
+// HeapRegions are kept in the _regions array in address order. A region's
+// index in the array corresponds to its index in the heap (i.e., 0 is the
+// region at the bottom of the heap, 1 is the one after it, etc.). Two
+// regions that are consecutive in the array should also be adjacent in the
+// address space (i.e., region(i).end() == region(i+1).bottom().
+//
+// We create a HeapRegion when we commit the region's address space
+// for the first time. When we uncommit the address space of a
+// region we retain the HeapRegion to be able to re-use it in the
+// future (in case we recommit it).
+//
+// We keep track of three lengths:
+//
+// * _num_committed (returned by length()) is the number of currently
+// committed regions. These may not be contiguous.
+// * _allocated_heapregions_length (not exposed outside this class) is the
+// number of regions+1 for which we have HeapRegions.
+// * max_length() returns the maximum number of regions the heap can have.
+//
+
+class HeapRegionManager: public CHeapObj<mtGC> {
+ friend class VMStructs;
+
+ G1HeapRegionTable _regions;
+
+ G1RegionToSpaceMapper* _heap_mapper;
+ G1RegionToSpaceMapper* _prev_bitmap_mapper;
+ G1RegionToSpaceMapper* _next_bitmap_mapper;
+ G1RegionToSpaceMapper* _bot_mapper;
+ G1RegionToSpaceMapper* _cardtable_mapper;
+ G1RegionToSpaceMapper* _card_counts_mapper;
+
+ FreeRegionList _free_list;
+
+ // Each bit in this bitmap indicates that the corresponding region is available
+ // for allocation.
+ BitMap _available_map;
+
+ // The number of regions committed in the heap.
+ uint _num_committed;
+
+ // Internal only. The highest heap region +1 we allocated a HeapRegion instance for.
+ uint _allocated_heapregions_length;
+
+ HeapWord* heap_bottom() const { return _regions.bottom_address_mapped(); }
+ HeapWord* heap_end() const {return _regions.end_address_mapped(); }
+
+ void make_regions_available(uint index, uint num_regions = 1);
+
+ // Pass down commit calls to the VirtualSpace.
+ void commit_regions(uint index, size_t num_regions = 1);
+ void uncommit_regions(uint index, size_t num_regions = 1);
+
+ // Notify other data structures about change in the heap layout.
+ void update_committed_space(HeapWord* old_end, HeapWord* new_end);
+ // Calculate the starting region for each worker during parallel iteration so
+ // that they do not all start from the same region.
+ uint start_region_for_worker(uint worker_i, uint num_workers, uint num_regions) const;
+
+ // Find a contiguous set of empty or uncommitted regions of length num and return
+ // the index of the first region or G1_NO_HRM_INDEX if the search was unsuccessful.
+ // If only_empty is true, only empty regions are considered.
+ // Searches from bottom to top of the heap, doing a first-fit.
+ uint find_contiguous(size_t num, bool only_empty);
+ // Finds the next sequence of unavailable regions starting from start_idx. Returns the
+ // length of the sequence found. If this result is zero, no such sequence could be found,
+ // otherwise res_idx indicates the start index of these regions.
+ uint find_unavailable_from_idx(uint start_idx, uint* res_idx) const;
+ // Finds the next sequence of empty regions starting from start_idx, going backwards in
+ // the heap. Returns the length of the sequence found. If this value is zero, no
+ // sequence could be found, otherwise res_idx contains the start index of this range.
+ uint find_empty_from_idx_reverse(uint start_idx, uint* res_idx) const;
+ // Allocate a new HeapRegion for the given index.
+ HeapRegion* new_heap_region(uint hrm_index);
+#ifdef ASSERT
+public:
+ bool is_free(HeapRegion* hr) const;
+#endif
+ // Returns whether the given region is available for allocation.
+ bool is_available(uint region) const;
+
+ public:
+ // Empty constructor, we'll initialize it with the initialize() method.
+ HeapRegionManager() : _regions(), _heap_mapper(NULL), _num_committed(0),
+ _next_bitmap_mapper(NULL), _prev_bitmap_mapper(NULL), _bot_mapper(NULL),
+ _allocated_heapregions_length(0), _available_map(),
+ _free_list("Free list", new MasterFreeRegionListMtSafeChecker())
+ { }
+
+ void initialize(G1RegionToSpaceMapper* heap_storage,
+ G1RegionToSpaceMapper* prev_bitmap,
+ G1RegionToSpaceMapper* next_bitmap,
+ G1RegionToSpaceMapper* bot,
+ G1RegionToSpaceMapper* cardtable,
+ G1RegionToSpaceMapper* card_counts);
+
+ // Return the "dummy" region used for G1AllocRegion. This is currently a hardwired
+ // new HeapRegion that owns HeapRegion at index 0. Since at the moment we commit
+ // the heap from the lowest address, this region (and its associated data
+ // structures) are available and we do not need to check further.
+ HeapRegion* get_dummy_region() { return new_heap_region(0); }
+
+ // Return the HeapRegion at the given index. Assume that the index
+ // is valid.
+ inline HeapRegion* at(uint index) const;
+
+ // If addr is within the committed space return its corresponding
+ // HeapRegion, otherwise return NULL.
+ inline HeapRegion* addr_to_region(HeapWord* addr) const;
+
+ // Insert the given region into the free region list.
+ inline void insert_into_free_list(HeapRegion* hr);
+
+ // Insert the given region list into the global free region list.
+ void insert_list_into_free_list(FreeRegionList* list) {
+ _free_list.add_ordered(list);
+ }
+
+ HeapRegion* allocate_free_region(bool is_old) {
+ HeapRegion* hr = _free_list.remove_region(is_old);
+
+ if (hr != NULL) {
+ assert(hr->next() == NULL, "Single region should not have next");
+ assert(is_available(hr->hrm_index()), "Must be committed");
+ }
+ return hr;
+ }
+
+ inline void allocate_free_regions_starting_at(uint first, uint num_regions);
+
+ // Remove all regions from the free list.
+ void remove_all_free_regions() {
+ _free_list.remove_all();
+ }
+
+ // Return the number of committed free regions in the heap.
+ uint num_free_regions() const {
+ return _free_list.length();
+ }
+
+ size_t total_capacity_bytes() const {
+ return num_free_regions() * HeapRegion::GrainBytes;
+ }
+
+ // Return the number of available (uncommitted) regions.
+ uint available() const { return max_length() - length(); }
+
+ // Return the number of regions that have been committed in the heap.
+ uint length() const { return _num_committed; }
+
+ // Return the maximum number of regions in the heap.
+ uint max_length() const { return (uint)_regions.length(); }
+
+ MemRegion reserved() const { return MemRegion(heap_bottom(), heap_end()); }
+
+ // Expand the sequence to reflect that the heap has grown. Either create new
+ // HeapRegions, or re-use existing ones. Returns the number of regions the
+ // sequence was expanded by. If a HeapRegion allocation fails, the resulting
+ // number of regions might be smaller than what's desired.
+ uint expand_by(uint num_regions);
+
+ // Makes sure that the regions from start to start+num_regions-1 are available
+ // for allocation. Returns the number of regions that were committed to achieve
+ // this.
+ uint expand_at(uint start, uint num_regions);
+
+ // Find a contiguous set of empty regions of length num. Returns the start index of
+ // that set, or G1_NO_HRM_INDEX.
+ uint find_contiguous_only_empty(size_t num) { return find_contiguous(num, true); }
+ // Find a contiguous set of empty or unavailable regions of length num. Returns the
+ // start index of that set, or G1_NO_HRM_INDEX.
+ uint find_contiguous_empty_or_unavailable(size_t num) { return find_contiguous(num, false); }
+
+ HeapRegion* next_region_in_heap(const HeapRegion* r) const;
+
+ // Apply blk->doHeapRegion() on all committed regions in address order,
+ // terminating the iteration early if doHeapRegion() returns true.
+ void iterate(HeapRegionClosure* blk) const;
+
+ void par_iterate(HeapRegionClosure* blk, uint worker_id, uint no_of_par_workers, jint claim_value) const;
+
+ // Uncommit up to num_regions_to_remove regions that are completely free.
+ // Return the actual number of uncommitted regions.
+ uint shrink_by(uint num_regions_to_remove);
+
+ void verify();
+
+ // Do some sanity checking.
+ void verify_optional() PRODUCT_RETURN;
+};
+
+#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONMANAGER_HPP
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.inline.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2001, 2014, 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_IMPLEMENTATION_G1_HEAPREGIONMANAGER_INLINE_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONMANAGER_INLINE_HPP
+
+#include "gc_implementation/g1/heapRegion.hpp"
+#include "gc_implementation/g1/heapRegionManager.hpp"
+#include "gc_implementation/g1/heapRegionSet.inline.hpp"
+
+inline HeapRegion* HeapRegionManager::addr_to_region(HeapWord* addr) const {
+ assert(addr < heap_end(),
+ err_msg("addr: "PTR_FORMAT" end: "PTR_FORMAT, p2i(addr), p2i(heap_end())));
+ assert(addr >= heap_bottom(),
+ err_msg("addr: "PTR_FORMAT" bottom: "PTR_FORMAT, p2i(addr), p2i(heap_bottom())));
+
+ HeapRegion* hr = _regions.get_by_address(addr);
+ return hr;
+}
+
+inline HeapRegion* HeapRegionManager::at(uint index) const {
+ assert(is_available(index), "pre-condition");
+ HeapRegion* hr = _regions.get_by_index(index);
+ assert(hr != NULL, "sanity");
+ assert(hr->hrm_index() == index, "sanity");
+ return hr;
+}
+
+inline void HeapRegionManager::insert_into_free_list(HeapRegion* hr) {
+ _free_list.add_ordered(hr);
+}
+
+inline void HeapRegionManager::allocate_free_regions_starting_at(uint first, uint num_regions) {
+ _free_list.remove_starting_at(at(first), num_regions);
+}
+
+#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONMANAGER_INLINE_HPP
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -27,7 +27,7 @@
#include "gc_implementation/g1/g1BlockOffsetTable.inline.hpp"
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#include "gc_implementation/g1/heapRegionRemSet.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
#include "memory/allocation.hpp"
#include "memory/padded.inline.hpp"
#include "memory/space.inline.hpp"
@@ -420,7 +420,7 @@
}
void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
- uint cur_hrs_ind = hr()->hrs_index();
+ uint cur_hrm_ind = hr()->hrm_index();
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr("ORT::add_reference_work(" PTR_FORMAT "->" PTR_FORMAT ").",
@@ -435,10 +435,10 @@
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = %d)",
hr()->bottom(), from_card,
- FromCardCache::at((uint)tid, cur_hrs_ind));
+ FromCardCache::at((uint)tid, cur_hrm_ind));
}
- if (FromCardCache::contains_or_replace((uint)tid, cur_hrs_ind, from_card)) {
+ if (FromCardCache::contains_or_replace((uint)tid, cur_hrm_ind, from_card)) {
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr(" from-card cache hit.");
}
@@ -448,7 +448,7 @@
// Note that this may be a continued H region.
HeapRegion* from_hr = _g1h->heap_region_containing_raw(from);
- RegionIdx_t from_hrs_ind = (RegionIdx_t) from_hr->hrs_index();
+ RegionIdx_t from_hrs_ind = (RegionIdx_t) from_hr->hrm_index();
// If the region is already coarsened, return.
if (_coarse_map.at(from_hrs_ind)) {
@@ -495,7 +495,7 @@
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr(" [tid %d] sparse table entry "
"overflow(f: %d, t: %u)",
- tid, from_hrs_ind, cur_hrs_ind);
+ tid, from_hrs_ind, cur_hrm_ind);
}
}
@@ -607,9 +607,9 @@
guarantee(max != NULL, "Since _n_fine_entries > 0");
// Set the corresponding coarse bit.
- size_t max_hrs_index = (size_t) max->hr()->hrs_index();
- if (!_coarse_map.at(max_hrs_index)) {
- _coarse_map.at_put(max_hrs_index, true);
+ size_t max_hrm_index = (size_t) max->hr()->hrm_index();
+ if (!_coarse_map.at(max_hrm_index)) {
+ _coarse_map.at_put(max_hrm_index, true);
_n_coarse_entries++;
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print("Coarsened entry in region [" PTR_FORMAT "...] "
@@ -633,7 +633,7 @@
BitMap* region_bm, BitMap* card_bm) {
// First eliminated garbage regions from the coarse map.
if (G1RSScrubVerbose) {
- gclog_or_tty->print_cr("Scrubbing region %u:", hr()->hrs_index());
+ gclog_or_tty->print_cr("Scrubbing region %u:", hr()->hrm_index());
}
assert(_coarse_map.size() == region_bm->size(), "Precondition");
@@ -656,9 +656,9 @@
// If the entire region is dead, eliminate.
if (G1RSScrubVerbose) {
gclog_or_tty->print_cr(" For other region %u:",
- cur->hr()->hrs_index());
+ cur->hr()->hrm_index());
}
- if (!region_bm->at((size_t) cur->hr()->hrs_index())) {
+ if (!region_bm->at((size_t) cur->hr()->hrm_index())) {
*prev = nxt;
cur->set_collision_list_next(NULL);
_n_fine_entries--;
@@ -752,7 +752,7 @@
}
void OtherRegionsTable::clear_fcc() {
- FromCardCache::clear(hr()->hrs_index());
+ FromCardCache::clear(hr()->hrm_index());
}
void OtherRegionsTable::clear() {
@@ -803,7 +803,7 @@
bool OtherRegionsTable::contains_reference_locked(OopOrNarrowOopStar from) const {
HeapRegion* hr = _g1h->heap_region_containing_raw(from);
- RegionIdx_t hr_ind = (RegionIdx_t) hr->hrs_index();
+ RegionIdx_t hr_ind = (RegionIdx_t) hr->hrm_index();
// Is this region in the coarse map?
if (_coarse_map.at(hr_ind)) return true;
@@ -840,7 +840,7 @@
HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa,
HeapRegion* hr)
: _bosa(bosa),
- _m(Mutex::leaf, FormatBuffer<128>("HeapRegionRemSet lock #%u", hr->hrs_index()), true),
+ _m(Mutex::leaf, FormatBuffer<128>("HeapRegionRemSet lock #%u", hr->hrm_index()), true),
_code_roots(), _other_regions(hr, &_m), _iter_state(Unclaimed), _iter_claimed(0) {
reset_for_par_iteration();
}
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp Thu Sep 04 13:26:26 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,450 +0,0 @@
-/*
- * Copyright (c) 2001, 2014, 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 "gc_implementation/g1/heapRegion.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
-#include "gc_implementation/g1/heapRegionSet.inline.hpp"
-#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
-#include "gc_implementation/g1/concurrentG1Refine.hpp"
-#include "memory/allocation.hpp"
-
-void HeapRegionSeq::initialize(G1RegionToSpaceMapper* heap_storage,
- G1RegionToSpaceMapper* prev_bitmap,
- G1RegionToSpaceMapper* next_bitmap,
- G1RegionToSpaceMapper* bot,
- G1RegionToSpaceMapper* cardtable,
- G1RegionToSpaceMapper* card_counts) {
- _allocated_heapregions_length = 0;
-
- _heap_mapper = heap_storage;
-
- _prev_bitmap_mapper = prev_bitmap;
- _next_bitmap_mapper = next_bitmap;
-
- _bot_mapper = bot;
- _cardtable_mapper = cardtable;
-
- _card_counts_mapper = card_counts;
-
- MemRegion reserved = heap_storage->reserved();
- _regions.initialize(reserved.start(), reserved.end(), HeapRegion::GrainBytes);
-
- _available_map.resize(_regions.length(), false);
- _available_map.clear();
-}
-
-bool HeapRegionSeq::is_available(uint region) const {
- return _available_map.at(region);
-}
-
-#ifdef ASSERT
-bool HeapRegionSeq::is_free(HeapRegion* hr) const {
- return _free_list.contains(hr);
-}
-#endif
-
-HeapRegion* HeapRegionSeq::new_heap_region(uint hrs_index) {
- HeapWord* bottom = G1CollectedHeap::heap()->bottom_addr_for_region(hrs_index);
- MemRegion mr(bottom, bottom + HeapRegion::GrainWords);
- assert(reserved().contains(mr), "invariant");
- return new HeapRegion(hrs_index, G1CollectedHeap::heap()->bot_shared(), mr);
-}
-
-void HeapRegionSeq::commit_regions(uint index, size_t num_regions) {
- guarantee(num_regions > 0, "Must commit more than zero regions");
- guarantee(_num_committed + num_regions <= max_length(), "Cannot commit more than the maximum amount of regions");
-
- _num_committed += (uint)num_regions;
-
- _heap_mapper->commit_regions(index, num_regions);
-
- // Also commit auxiliary data
- _prev_bitmap_mapper->commit_regions(index, num_regions);
- _next_bitmap_mapper->commit_regions(index, num_regions);
-
- _bot_mapper->commit_regions(index, num_regions);
- _cardtable_mapper->commit_regions(index, num_regions);
-
- _card_counts_mapper->commit_regions(index, num_regions);
-}
-
-void HeapRegionSeq::uncommit_regions(uint start, size_t num_regions) {
- guarantee(num_regions >= 1, err_msg("Need to specify at least one region to uncommit, tried to uncommit zero regions at %u", start));
- guarantee(_num_committed >= num_regions, "pre-condition");
-
- // Print before uncommitting.
- if (G1CollectedHeap::heap()->hr_printer()->is_active()) {
- for (uint i = start; i < start + num_regions; i++) {
- HeapRegion* hr = at(i);
- G1CollectedHeap::heap()->hr_printer()->uncommit(hr->bottom(), hr->end());
- }
- }
-
- _num_committed -= (uint)num_regions;
-
- _available_map.par_clear_range(start, start + num_regions, BitMap::unknown_range);
- _heap_mapper->uncommit_regions(start, num_regions);
-
- // Also uncommit auxiliary data
- _prev_bitmap_mapper->uncommit_regions(start, num_regions);
- _next_bitmap_mapper->uncommit_regions(start, num_regions);
-
- _bot_mapper->uncommit_regions(start, num_regions);
- _cardtable_mapper->uncommit_regions(start, num_regions);
-
- _card_counts_mapper->uncommit_regions(start, num_regions);
-}
-
-void HeapRegionSeq::make_regions_available(uint start, uint num_regions) {
- guarantee(num_regions > 0, "No point in calling this for zero regions");
- commit_regions(start, num_regions);
- for (uint i = start; i < start + num_regions; i++) {
- if (_regions.get_by_index(i) == NULL) {
- HeapRegion* new_hr = new_heap_region(i);
- _regions.set_by_index(i, new_hr);
- _allocated_heapregions_length = MAX2(_allocated_heapregions_length, i + 1);
- }
- }
-
- _available_map.par_set_range(start, start + num_regions, BitMap::unknown_range);
-
- for (uint i = start; i < start + num_regions; i++) {
- assert(is_available(i), err_msg("Just made region %u available but is apparently not.", i));
- HeapRegion* hr = at(i);
- if (G1CollectedHeap::heap()->hr_printer()->is_active()) {
- G1CollectedHeap::heap()->hr_printer()->commit(hr->bottom(), hr->end());
- }
- HeapWord* bottom = G1CollectedHeap::heap()->bottom_addr_for_region(i);
- MemRegion mr(bottom, bottom + HeapRegion::GrainWords);
-
- hr->initialize(mr);
- insert_into_free_list(at(i));
- }
-}
-
-uint HeapRegionSeq::expand_by(uint num_regions) {
- return expand_at(0, num_regions);
-}
-
-uint HeapRegionSeq::expand_at(uint start, uint num_regions) {
- if (num_regions == 0) {
- return 0;
- }
-
- uint cur = start;
- uint idx_last_found = 0;
- uint num_last_found = 0;
-
- uint expanded = 0;
-
- while (expanded < num_regions &&
- (num_last_found = find_unavailable_from_idx(cur, &idx_last_found)) > 0) {
- uint to_expand = MIN2(num_regions - expanded, num_last_found);
- make_regions_available(idx_last_found, to_expand);
- expanded += to_expand;
- cur = idx_last_found + num_last_found + 1;
- }
-
- verify_optional();
- return expanded;
-}
-
-uint HeapRegionSeq::find_contiguous(size_t num, bool empty_only) {
- uint found = 0;
- size_t length_found = 0;
- uint cur = 0;
-
- while (length_found < num && cur < max_length()) {
- HeapRegion* hr = _regions.get_by_index(cur);
- if ((!empty_only && !is_available(cur)) || (is_available(cur) && hr != NULL && hr->is_empty())) {
- // This region is a potential candidate for allocation into.
- length_found++;
- } else {
- // This region is not a candidate. The next region is the next possible one.
- found = cur + 1;
- length_found = 0;
- }
- cur++;
- }
-
- if (length_found == num) {
- for (uint i = found; i < (found + num); i++) {
- HeapRegion* hr = _regions.get_by_index(i);
- // sanity check
- guarantee((!empty_only && !is_available(i)) || (is_available(i) && hr != NULL && hr->is_empty()),
- err_msg("Found region sequence starting at " UINT32_FORMAT ", length " SIZE_FORMAT
- " that is not empty at " UINT32_FORMAT ". Hr is " PTR_FORMAT, found, num, i, p2i(hr)));
- }
- return found;
- } else {
- return G1_NO_HRS_INDEX;
- }
-}
-
-HeapRegion* HeapRegionSeq::next_region_in_heap(const HeapRegion* r) const {
- guarantee(r != NULL, "Start region must be a valid region");
- guarantee(is_available(r->hrs_index()), err_msg("Trying to iterate starting from region %u which is not in the heap", r->hrs_index()));
- for (uint i = r->hrs_index() + 1; i < _allocated_heapregions_length; i++) {
- HeapRegion* hr = _regions.get_by_index(i);
- if (is_available(i)) {
- return hr;
- }
- }
- return NULL;
-}
-
-void HeapRegionSeq::iterate(HeapRegionClosure* blk) const {
- uint len = max_length();
-
- for (uint i = 0; i < len; i++) {
- if (!is_available(i)) {
- continue;
- }
- guarantee(at(i) != NULL, err_msg("Tried to access region %u that has a NULL HeapRegion*", i));
- bool res = blk->doHeapRegion(at(i));
- if (res) {
- blk->incomplete();
- return;
- }
- }
-}
-
-uint HeapRegionSeq::find_unavailable_from_idx(uint start_idx, uint* res_idx) const {
- guarantee(res_idx != NULL, "checking");
- guarantee(start_idx <= (max_length() + 1), "checking");
-
- uint num_regions = 0;
-
- uint cur = start_idx;
- while (cur < max_length() && is_available(cur)) {
- cur++;
- }
- if (cur == max_length()) {
- return num_regions;
- }
- *res_idx = cur;
- while (cur < max_length() && !is_available(cur)) {
- cur++;
- }
- num_regions = cur - *res_idx;
-#ifdef ASSERT
- for (uint i = *res_idx; i < (*res_idx + num_regions); i++) {
- assert(!is_available(i), "just checking");
- }
- assert(cur == max_length() || num_regions == 0 || is_available(cur),
- err_msg("The region at the current position %u must be available or at the end of the heap.", cur));
-#endif
- return num_regions;
-}
-
-uint HeapRegionSeq::start_region_for_worker(uint worker_i, uint num_workers, uint num_regions) const {
- return num_regions * worker_i / num_workers;
-}
-
-void HeapRegionSeq::par_iterate(HeapRegionClosure* blk, uint worker_id, uint num_workers, jint claim_value) const {
- const uint start_index = start_region_for_worker(worker_id, num_workers, _allocated_heapregions_length);
-
- // Every worker will actually look at all regions, skipping over regions that
- // are currently not committed.
- // This also (potentially) iterates over regions newly allocated during GC. This
- // is no problem except for some extra work.
- for (uint count = 0; count < _allocated_heapregions_length; count++) {
- const uint index = (start_index + count) % _allocated_heapregions_length;
- assert(0 <= index && index < _allocated_heapregions_length, "sanity");
- // Skip over unavailable regions
- if (!is_available(index)) {
- continue;
- }
- HeapRegion* r = _regions.get_by_index(index);
- // We'll ignore "continues humongous" regions (we'll process them
- // when we come across their corresponding "start humongous"
- // region) and regions already claimed.
- if (r->claim_value() == claim_value || r->continuesHumongous()) {
- continue;
- }
- // OK, try to claim it
- if (!r->claimHeapRegion(claim_value)) {
- continue;
- }
- // Success!
- if (r->startsHumongous()) {
- // If the region is "starts humongous" we'll iterate over its
- // "continues humongous" first; in fact we'll do them
- // first. The order is important. In one case, calling the
- // closure on the "starts humongous" region might de-allocate
- // and clear all its "continues humongous" regions and, as a
- // result, we might end up processing them twice. So, we'll do
- // them first (note: most closures will ignore them anyway) and
- // then we'll do the "starts humongous" region.
- for (uint ch_index = index + 1; ch_index < index + r->region_num(); ch_index++) {
- HeapRegion* chr = _regions.get_by_index(ch_index);
-
- assert(chr->continuesHumongous(), "Must be humongous region");
- assert(chr->humongous_start_region() == r,
- err_msg("Must work on humongous continuation of the original start region "
- PTR_FORMAT ", but is " PTR_FORMAT, p2i(r), p2i(chr)));
- assert(chr->claim_value() != claim_value,
- "Must not have been claimed yet because claiming of humongous continuation first claims the start region");
-
- bool claim_result = chr->claimHeapRegion(claim_value);
- // We should always be able to claim it; no one else should
- // be trying to claim this region.
- guarantee(claim_result, "We should always be able to claim the continuesHumongous part of the humongous object");
-
- bool res2 = blk->doHeapRegion(chr);
- if (res2) {
- return;
- }
-
- // Right now, this holds (i.e., no closure that actually
- // does something with "continues humongous" regions
- // clears them). We might have to weaken it in the future,
- // but let's leave these two asserts here for extra safety.
- assert(chr->continuesHumongous(), "should still be the case");
- assert(chr->humongous_start_region() == r, "sanity");
- }
- }
-
- bool res = blk->doHeapRegion(r);
- if (res) {
- return;
- }
- }
-}
-
-uint HeapRegionSeq::shrink_by(uint num_regions_to_remove) {
- assert(length() > 0, "the region sequence should not be empty");
- assert(length() <= _allocated_heapregions_length, "invariant");
- assert(_allocated_heapregions_length > 0, "we should have at least one region committed");
- assert(num_regions_to_remove < length(), "We should never remove all regions");
-
- if (num_regions_to_remove == 0) {
- return 0;
- }
-
- uint removed = 0;
- uint cur = _allocated_heapregions_length - 1;
- uint idx_last_found = 0;
- uint num_last_found = 0;
-
- while ((removed < num_regions_to_remove) &&
- (num_last_found = find_empty_from_idx_reverse(cur, &idx_last_found)) > 0) {
- // Only allow uncommit from the end of the heap.
- if ((idx_last_found + num_last_found) != _allocated_heapregions_length) {
- return 0;
- }
- uint to_remove = MIN2(num_regions_to_remove - removed, num_last_found);
-
- uncommit_regions(idx_last_found + num_last_found - to_remove, to_remove);
-
- cur -= num_last_found;
- removed += to_remove;
- }
-
- verify_optional();
-
- return removed;
-}
-
-uint HeapRegionSeq::find_empty_from_idx_reverse(uint start_idx, uint* res_idx) const {
- guarantee(start_idx < _allocated_heapregions_length, "checking");
- guarantee(res_idx != NULL, "checking");
-
- uint num_regions_found = 0;
-
- jlong cur = start_idx;
- while (cur != -1 && !(is_available(cur) && at(cur)->is_empty())) {
- cur--;
- }
- if (cur == -1) {
- return num_regions_found;
- }
- jlong old_cur = cur;
- // cur indexes the first empty region
- while (cur != -1 && is_available(cur) && at(cur)->is_empty()) {
- cur--;
- }
- *res_idx = cur + 1;
- num_regions_found = old_cur - cur;
-
-#ifdef ASSERT
- for (uint i = *res_idx; i < (*res_idx + num_regions_found); i++) {
- assert(at(i)->is_empty(), "just checking");
- }
-#endif
- return num_regions_found;
-}
-
-void HeapRegionSeq::verify() {
- guarantee(length() <= _allocated_heapregions_length,
- err_msg("invariant: _length: %u _allocated_length: %u",
- length(), _allocated_heapregions_length));
- guarantee(_allocated_heapregions_length <= max_length(),
- err_msg("invariant: _allocated_length: %u _max_length: %u",
- _allocated_heapregions_length, max_length()));
-
- bool prev_committed = true;
- uint num_committed = 0;
- HeapWord* prev_end = heap_bottom();
- for (uint i = 0; i < _allocated_heapregions_length; i++) {
- if (!is_available(i)) {
- prev_committed = false;
- continue;
- }
- num_committed++;
- HeapRegion* hr = _regions.get_by_index(i);
- guarantee(hr != NULL, err_msg("invariant: i: %u", i));
- guarantee(!prev_committed || hr->bottom() == prev_end,
- err_msg("invariant i: %u "HR_FORMAT" prev_end: "PTR_FORMAT,
- i, HR_FORMAT_PARAMS(hr), p2i(prev_end)));
- guarantee(hr->hrs_index() == i,
- err_msg("invariant: i: %u hrs_index(): %u", i, hr->hrs_index()));
- // Asserts will fire if i is >= _length
- HeapWord* addr = hr->bottom();
- guarantee(addr_to_region(addr) == hr, "sanity");
- // We cannot check whether the region is part of a particular set: at the time
- // this method may be called, we have only completed allocation of the regions,
- // but not put into a region set.
- prev_committed = true;
- if (hr->startsHumongous()) {
- prev_end = hr->orig_end();
- } else {
- prev_end = hr->end();
- }
- }
- for (uint i = _allocated_heapregions_length; i < max_length(); i++) {
- guarantee(_regions.get_by_index(i) == NULL, err_msg("invariant i: %u", i));
- }
-
- guarantee(num_committed == _num_committed, err_msg("Found %u committed regions, but should be %u", num_committed, _num_committed));
- _free_list.verify();
-}
-
-#ifndef PRODUCT
-void HeapRegionSeq::verify_optional() {
- verify();
-}
-#endif // PRODUCT
-
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp Thu Sep 04 13:26:26 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,239 +0,0 @@
-/*
- * Copyright (c) 2001, 2013, 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_IMPLEMENTATION_G1_HEAPREGIONSEQ_HPP
-#define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSEQ_HPP
-
-#include "gc_implementation/g1/g1BiasedArray.hpp"
-#include "gc_implementation/g1/g1RegionToSpaceMapper.hpp"
-#include "gc_implementation/g1/heapRegionSet.hpp"
-
-class HeapRegion;
-class HeapRegionClosure;
-class FreeRegionList;
-
-class G1HeapRegionTable : public G1BiasedMappedArray<HeapRegion*> {
- protected:
- virtual HeapRegion* default_value() const { return NULL; }
-};
-
-// This class keeps track of the actual heap memory, auxiliary data
-// and its metadata (i.e., HeapRegion instances) and the list of free regions.
-//
-// This allows maximum flexibility for deciding what to commit or uncommit given
-// a request from outside.
-//
-// HeapRegions are kept in the _regions array in address order. A region's
-// index in the array corresponds to its index in the heap (i.e., 0 is the
-// region at the bottom of the heap, 1 is the one after it, etc.). Two
-// regions that are consecutive in the array should also be adjacent in the
-// address space (i.e., region(i).end() == region(i+1).bottom().
-//
-// We create a HeapRegion when we commit the region's address space
-// for the first time. When we uncommit the address space of a
-// region we retain the HeapRegion to be able to re-use it in the
-// future (in case we recommit it).
-//
-// We keep track of three lengths:
-//
-// * _num_committed (returned by length()) is the number of currently
-// committed regions. These may not be contiguous.
-// * _allocated_heapregions_length (not exposed outside this class) is the
-// number of regions+1 for which we have HeapRegions.
-// * max_length() returns the maximum number of regions the heap can have.
-//
-
-class HeapRegionSeq: public CHeapObj<mtGC> {
- friend class VMStructs;
-
- G1HeapRegionTable _regions;
-
- G1RegionToSpaceMapper* _heap_mapper;
- G1RegionToSpaceMapper* _prev_bitmap_mapper;
- G1RegionToSpaceMapper* _next_bitmap_mapper;
- G1RegionToSpaceMapper* _bot_mapper;
- G1RegionToSpaceMapper* _cardtable_mapper;
- G1RegionToSpaceMapper* _card_counts_mapper;
-
- FreeRegionList _free_list;
-
- // Each bit in this bitmap indicates that the corresponding region is available
- // for allocation.
- BitMap _available_map;
-
- // The number of regions committed in the heap.
- uint _num_committed;
-
- // Internal only. The highest heap region +1 we allocated a HeapRegion instance for.
- uint _allocated_heapregions_length;
-
- HeapWord* heap_bottom() const { return _regions.bottom_address_mapped(); }
- HeapWord* heap_end() const {return _regions.end_address_mapped(); }
-
- void make_regions_available(uint index, uint num_regions = 1);
-
- // Pass down commit calls to the VirtualSpace.
- void commit_regions(uint index, size_t num_regions = 1);
- void uncommit_regions(uint index, size_t num_regions = 1);
-
- // Notify other data structures about change in the heap layout.
- void update_committed_space(HeapWord* old_end, HeapWord* new_end);
- // Calculate the starting region for each worker during parallel iteration so
- // that they do not all start from the same region.
- uint start_region_for_worker(uint worker_i, uint num_workers, uint num_regions) const;
-
- // Find a contiguous set of empty or uncommitted regions of length num and return
- // the index of the first region or G1_NO_HRS_INDEX if the search was unsuccessful.
- // If only_empty is true, only empty regions are considered.
- // Searches from bottom to top of the heap, doing a first-fit.
- uint find_contiguous(size_t num, bool only_empty);
- // Finds the next sequence of unavailable regions starting from start_idx. Returns the
- // length of the sequence found. If this result is zero, no such sequence could be found,
- // otherwise res_idx indicates the start index of these regions.
- uint find_unavailable_from_idx(uint start_idx, uint* res_idx) const;
- // Finds the next sequence of empty regions starting from start_idx, going backwards in
- // the heap. Returns the length of the sequence found. If this value is zero, no
- // sequence could be found, otherwise res_idx contains the start index of this range.
- uint find_empty_from_idx_reverse(uint start_idx, uint* res_idx) const;
- // Allocate a new HeapRegion for the given index.
- HeapRegion* new_heap_region(uint hrs_index);
-#ifdef ASSERT
-public:
- bool is_free(HeapRegion* hr) const;
-#endif
- // Returns whether the given region is available for allocation.
- bool is_available(uint region) const;
-
- public:
- // Empty constructor, we'll initialize it with the initialize() method.
- HeapRegionSeq() : _regions(), _heap_mapper(NULL), _num_committed(0),
- _next_bitmap_mapper(NULL), _prev_bitmap_mapper(NULL), _bot_mapper(NULL),
- _allocated_heapregions_length(0), _available_map(),
- _free_list("Free list", new MasterFreeRegionListMtSafeChecker())
- { }
-
- void initialize(G1RegionToSpaceMapper* heap_storage,
- G1RegionToSpaceMapper* prev_bitmap,
- G1RegionToSpaceMapper* next_bitmap,
- G1RegionToSpaceMapper* bot,
- G1RegionToSpaceMapper* cardtable,
- G1RegionToSpaceMapper* card_counts);
-
- // Return the "dummy" region used for G1AllocRegion. This is currently a hardwired
- // new HeapRegion that owns HeapRegion at index 0. Since at the moment we commit
- // the heap from the lowest address, this region (and its associated data
- // structures) are available and we do not need to check further.
- HeapRegion* get_dummy_region() { return new_heap_region(0); }
-
- // Return the HeapRegion at the given index. Assume that the index
- // is valid.
- inline HeapRegion* at(uint index) const;
-
- // If addr is within the committed space return its corresponding
- // HeapRegion, otherwise return NULL.
- inline HeapRegion* addr_to_region(HeapWord* addr) const;
-
- // Insert the given region into the free region list.
- inline void insert_into_free_list(HeapRegion* hr);
-
- // Insert the given region list into the global free region list.
- void insert_list_into_free_list(FreeRegionList* list) {
- _free_list.add_ordered(list);
- }
-
- HeapRegion* allocate_free_region(bool is_old) {
- HeapRegion* hr = _free_list.remove_region(is_old);
-
- if (hr != NULL) {
- assert(hr->next() == NULL, "Single region should not have next");
- assert(is_available(hr->hrs_index()), "Must be committed");
- }
- return hr;
- }
-
- inline void allocate_free_regions_starting_at(uint first, uint num_regions);
-
- // Remove all regions from the free list.
- void remove_all_free_regions() {
- _free_list.remove_all();
- }
-
- // Return the number of committed free regions in the heap.
- uint num_free_regions() const {
- return _free_list.length();
- }
-
- size_t total_capacity_bytes() const {
- return num_free_regions() * HeapRegion::GrainBytes;
- }
-
- // Return the number of available (uncommitted) regions.
- uint available() const { return max_length() - length(); }
-
- // Return the number of regions that have been committed in the heap.
- uint length() const { return _num_committed; }
-
- // Return the maximum number of regions in the heap.
- uint max_length() const { return (uint)_regions.length(); }
-
- MemRegion reserved() const { return MemRegion(heap_bottom(), heap_end()); }
-
- // Expand the sequence to reflect that the heap has grown. Either create new
- // HeapRegions, or re-use existing ones. Returns the number of regions the
- // sequence was expanded by. If a HeapRegion allocation fails, the resulting
- // number of regions might be smaller than what's desired.
- uint expand_by(uint num_regions);
-
- // Makes sure that the regions from start to start+num_regions-1 are available
- // for allocation. Returns the number of regions that were committed to achieve
- // this.
- uint expand_at(uint start, uint num_regions);
-
- // Find a contiguous set of empty regions of length num. Returns the start index of
- // that set, or G1_NO_HRS_INDEX.
- uint find_contiguous_only_empty(size_t num) { return find_contiguous(num, true); }
- // Find a contiguous set of empty or unavailable regions of length num. Returns the
- // start index of that set, or G1_NO_HRS_INDEX.
- uint find_contiguous_empty_or_unavailable(size_t num) { return find_contiguous(num, false); }
-
- HeapRegion* next_region_in_heap(const HeapRegion* r) const;
-
- // Apply blk->doHeapRegion() on all committed regions in address order,
- // terminating the iteration early if doHeapRegion() returns true.
- void iterate(HeapRegionClosure* blk) const;
-
- void par_iterate(HeapRegionClosure* blk, uint worker_id, uint no_of_par_workers, jint claim_value) const;
-
- // Uncommit up to num_regions_to_remove regions that are completely free.
- // Return the actual number of uncommitted regions.
- uint shrink_by(uint num_regions_to_remove);
-
- void verify();
-
- // Do some sanity checking.
- void verify_optional() PRODUCT_RETURN;
-};
-
-#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSEQ_HPP
-
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.inline.hpp Thu Sep 04 13:26:26 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2001, 2014, 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_IMPLEMENTATION_G1_HEAPREGIONSEQ_INLINE_HPP
-#define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSEQ_INLINE_HPP
-
-#include "gc_implementation/g1/heapRegion.hpp"
-#include "gc_implementation/g1/heapRegionSeq.hpp"
-#include "gc_implementation/g1/heapRegionSet.inline.hpp"
-
-inline HeapRegion* HeapRegionSeq::addr_to_region(HeapWord* addr) const {
- assert(addr < heap_end(),
- err_msg("addr: "PTR_FORMAT" end: "PTR_FORMAT, p2i(addr), p2i(heap_end())));
- assert(addr >= heap_bottom(),
- err_msg("addr: "PTR_FORMAT" bottom: "PTR_FORMAT, p2i(addr), p2i(heap_bottom())));
-
- HeapRegion* hr = _regions.get_by_address(addr);
- return hr;
-}
-
-inline HeapRegion* HeapRegionSeq::at(uint index) const {
- assert(is_available(index), "pre-condition");
- HeapRegion* hr = _regions.get_by_index(index);
- assert(hr != NULL, "sanity");
- assert(hr->hrs_index() == index, "sanity");
- return hr;
-}
-
-inline void HeapRegionSeq::insert_into_free_list(HeapRegion* hr) {
- _free_list.add_ordered(hr);
-}
-
-inline void HeapRegionSeq::allocate_free_regions_starting_at(uint first, uint num_regions) {
- _free_list.remove_starting_at(at(first), num_regions);
-}
-
-#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSEQ_INLINE_HPP
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -39,11 +39,11 @@
#ifndef PRODUCT
void HeapRegionSetBase::verify_region(HeapRegion* hr) {
- assert(hr->containing_set() == this, err_msg("Inconsistent containing set for %u", hr->hrs_index()));
- assert(!hr->is_young(), err_msg("Adding young region %u", hr->hrs_index())); // currently we don't use these sets for young regions
- assert(hr->isHumongous() == regions_humongous(), err_msg("Wrong humongous state for region %u and set %s", hr->hrs_index(), name()));
- assert(hr->is_empty() == regions_empty(), err_msg("Wrong empty state for region %u and set %s", hr->hrs_index(), name()));
- assert(hr->rem_set()->verify_ready_for_par_iteration(), err_msg("Wrong iteration state %u", hr->hrs_index()));
+ assert(hr->containing_set() == this, err_msg("Inconsistent containing set for %u", hr->hrm_index()));
+ assert(!hr->is_young(), err_msg("Adding young region %u", hr->hrm_index())); // currently we don't use these sets for young regions
+ assert(hr->isHumongous() == regions_humongous(), err_msg("Wrong humongous state for region %u and set %s", hr->hrm_index(), name()));
+ assert(hr->is_empty() == regions_empty(), err_msg("Wrong empty state for region %u and set %s", hr->hrm_index(), name()));
+ assert(hr->rem_set()->verify_ready_for_par_iteration(), err_msg("Wrong iteration state %u", hr->hrm_index()));
}
#endif
@@ -158,7 +158,7 @@
HeapRegion* curr_from = from_list->_head;
while (curr_from != NULL) {
- while (curr_to != NULL && curr_to->hrs_index() < curr_from->hrs_index()) {
+ while (curr_to != NULL && curr_to->hrm_index() < curr_from->hrm_index()) {
curr_to = curr_to->next();
}
@@ -183,7 +183,7 @@
}
}
- if (_tail->hrs_index() < from_list->_tail->hrs_index()) {
+ if (_tail->hrm_index() < from_list->_tail->hrm_index()) {
_tail = from_list->_tail;
}
}
@@ -309,8 +309,8 @@
if (curr->next() != NULL) {
guarantee(curr->next()->prev() == curr, "Next or prev pointers messed up");
}
- guarantee(curr->hrs_index() == 0 || curr->hrs_index() > last_index, "List should be sorted");
- last_index = curr->hrs_index();
+ guarantee(curr->hrm_index() == 0 || curr->hrm_index() > last_index, "List should be sorted");
+ last_index = curr->hrm_index();
capacity += curr->capacity();
@@ -319,7 +319,7 @@
curr = curr->next();
}
- guarantee(_tail == prev0, err_msg("Expected %s to end with %u but it ended with %u.", name(), _tail->hrs_index(), prev0->hrs_index()));
+ guarantee(_tail == prev0, err_msg("Expected %s to end with %u but it ended with %u.", name(), _tail->hrm_index(), prev0->hrm_index()));
guarantee(_tail == NULL || _tail->next() == NULL, "_tail should not have a next");
guarantee(length() == count, err_msg("%s count mismatch. Expected %u, actual %u.", name(), length(), count));
guarantee(total_capacity_bytes() == capacity, err_msg("%s capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT,
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -238,14 +238,14 @@
// Add hr to the list. The region should not be a member of another set.
// Assumes that the list is ordered and will preserve that order. The order
- // is determined by hrs_index.
+ // is determined by hrm_index.
inline void add_ordered(HeapRegion* hr);
// Removes from head or tail based on the given argument.
HeapRegion* remove_region(bool from_head);
// Merge two ordered lists. The result is also ordered. The order is
- // determined by hrs_index.
+ // determined by hrm_index.
void add_ordered(FreeRegionList* from_list);
// It empties the list by removing all regions from it.
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -60,14 +60,14 @@
if (_head != NULL) {
HeapRegion* curr;
- if (_last != NULL && _last->hrs_index() < hr->hrs_index()) {
+ if (_last != NULL && _last->hrm_index() < hr->hrm_index()) {
curr = _last;
} else {
curr = _head;
}
// Find first entry with a Region Index larger than entry to insert.
- while (curr != NULL && curr->hrs_index() < hr->hrs_index()) {
+ while (curr != NULL && curr->hrm_index() < hr->hrm_index()) {
curr = curr->next();
}
--- a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -453,7 +453,7 @@
bool SparsePRT::add_card(RegionIdx_t region_id, CardIdx_t card_index) {
#if SPARSE_PRT_VERBOSE
gclog_or_tty->print_cr(" Adding card %d from region %d to region %u sparse.",
- card_index, region_id, _hr->hrs_index());
+ card_index, region_id, _hr->hrm_index());
#endif
if (_next->occupied_entries() * 2 > _next->capacity()) {
expand();
@@ -505,7 +505,7 @@
#if SPARSE_PRT_VERBOSE
gclog_or_tty->print_cr(" Expanded sparse table for %u to %d.",
- _hr->hrs_index(), _next->capacity());
+ _hr->hrm_index(), _next->capacity());
#endif
for (size_t i = 0; i < last->capacity(); i++) {
SparsePRTEntry* e = last->entry((int)i);
--- a/hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -26,7 +26,7 @@
#define SHARE_VM_GC_IMPLEMENTATION_G1_VMSTRUCTS_G1_HPP
#include "gc_implementation/g1/heapRegion.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#define VM_STRUCTS_G1(nonstatic_field, static_field) \
@@ -42,10 +42,10 @@
nonstatic_field(G1HeapRegionTable, _bias, size_t) \
nonstatic_field(G1HeapRegionTable, _shift_by, uint) \
\
- nonstatic_field(HeapRegionSeq, _regions, G1HeapRegionTable) \
- nonstatic_field(HeapRegionSeq, _num_committed, uint) \
+ nonstatic_field(HeapRegionManager, _regions, G1HeapRegionTable) \
+ nonstatic_field(HeapRegionManager, _num_committed, uint) \
\
- nonstatic_field(G1CollectedHeap, _hrs, HeapRegionSeq) \
+ nonstatic_field(G1CollectedHeap, _hrm, HeapRegionManager) \
nonstatic_field(G1CollectedHeap, _summary_bytes_used, size_t) \
nonstatic_field(G1CollectedHeap, _g1mm, G1MonitoringSupport*) \
nonstatic_field(G1CollectedHeap, _old_set, HeapRegionSetBase) \
@@ -72,7 +72,7 @@
\
declare_type(G1OffsetTableContigSpace, CompactibleSpace) \
declare_type(HeapRegion, G1OffsetTableContigSpace) \
- declare_toplevel_type(HeapRegionSeq) \
+ declare_toplevel_type(HeapRegionManager) \
declare_toplevel_type(HeapRegionSetBase) \
declare_toplevel_type(HeapRegionSetCount) \
declare_toplevel_type(G1MonitoringSupport) \
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psGenerationCounters.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psGenerationCounters.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -30,6 +30,8 @@
PSGenerationCounters::PSGenerationCounters(const char* name,
int ordinal, int spaces,
+ size_t min_capacity,
+ size_t max_capacity,
PSVirtualSpace* v):
_ps_virtual_space(v) {
@@ -52,11 +54,11 @@
cname = PerfDataManager::counter_name(_name_space, "minCapacity");
PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_Bytes,
- _ps_virtual_space->committed_size(), CHECK);
+ min_capacity, CHECK);
cname = PerfDataManager::counter_name(_name_space, "maxCapacity");
PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_Bytes,
- _ps_virtual_space->reserved_size(), CHECK);
+ max_capacity, CHECK);
cname = PerfDataManager::counter_name(_name_space, "capacity");
_current_size = PerfDataManager::create_variable(SUN_GC, cname,
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psGenerationCounters.hpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psGenerationCounters.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -41,7 +41,7 @@
public:
PSGenerationCounters(const char* name, int ordinal, int spaces,
- PSVirtualSpace* v);
+ size_t min_capacity, size_t max_capacity, PSVirtualSpace* v);
void update_all() {
assert(_virtual_space == NULL, "Only one should be in use");
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -149,8 +149,8 @@
void PSOldGen::initialize_performance_counters(const char* perf_data_name, int level) {
// Generation Counters, generation 'level', 1 subspace
- _gen_counters = new PSGenerationCounters(perf_data_name, level, 1,
- virtual_space());
+ _gen_counters = new PSGenerationCounters(perf_data_name, level, 1, _min_gen_size,
+ _max_gen_size, virtual_space());
_space_counters = new SpaceCounters(perf_data_name, 0,
virtual_space()->reserved_size(),
_object_space, _gen_counters);
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -101,7 +101,8 @@
}
// Generation Counters - generation 0, 3 subspaces
- _gen_counters = new PSGenerationCounters("new", 0, 3, _virtual_space);
+ _gen_counters = new PSGenerationCounters("new", 0, 3, _min_gen_size,
+ _max_gen_size, _virtual_space);
// Compute maximum space sizes for performance counters
ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
--- a/hotspot/src/share/vm/gc_implementation/shared/generationCounters.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/shared/generationCounters.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -62,11 +62,12 @@
GenerationCounters::GenerationCounters(const char* name,
int ordinal, int spaces,
+ size_t min_capacity, size_t max_capacity,
VirtualSpace* v)
: _virtual_space(v) {
assert(v != NULL, "don't call this constructor if v == NULL");
initialize(name, ordinal, spaces,
- v->committed_size(), v->reserved_size(), v->committed_size());
+ min_capacity, max_capacity, v->committed_size());
}
GenerationCounters::GenerationCounters(const char* name,
--- a/hotspot/src/share/vm/gc_implementation/shared/generationCounters.hpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/shared/generationCounters.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -66,7 +66,7 @@
public:
GenerationCounters(const char* name, int ordinal, int spaces,
- VirtualSpace* v);
+ size_t min_capacity, size_t max_capacity, VirtualSpace* v);
~GenerationCounters() {
if (_name_space != NULL) FREE_C_HEAP_ARRAY(char, _name_space, mtGC);
--- a/hotspot/src/share/vm/memory/defNewGeneration.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/memory/defNewGeneration.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -214,9 +214,11 @@
_max_eden_size = size - (2*_max_survivor_size);
// allocate the performance counters
+ GenCollectorPolicy* gcp = (GenCollectorPolicy*) GenCollectedHeap::heap()->collector_policy();
// Generation counters -- generation 0, 3 subspaces
- _gen_counters = new GenerationCounters("new", 0, 3, &_virtual_space);
+ _gen_counters = new GenerationCounters("new", 0, 3,
+ gcp->min_young_size(), gcp->max_young_size(), &_virtual_space);
_gc_counters = new CollectorCounters(policy, 0);
_eden_counters = new CSpaceCounters("eden", 0, _max_eden_size, _eden_space,
--- a/hotspot/src/share/vm/memory/filemap.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/memory/filemap.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -445,7 +445,7 @@
// close and remove the file. See bug 6372906.
close();
remove(_full_path);
- fail_stop("Unable to write to shared archive file.", NULL);
+ fail_stop("Unable to write to shared archive file.");
}
}
_file_offset += nbytes;
@@ -463,7 +463,7 @@
// that the written file is the correct length.
_file_offset -= 1;
if (lseek(_fd, _file_offset, SEEK_SET) < 0) {
- fail_stop("Unable to seek.", NULL);
+ fail_stop("Unable to seek.");
}
char zero = 0;
write_bytes(&zero, 1);
@@ -534,7 +534,7 @@
// other reserved memory (like the code cache).
ReservedSpace rs(size, os::vm_allocation_granularity(), false, requested_addr);
if (!rs.is_reserved()) {
- fail_continue(err_msg("Unable to reserve shared space at required address " INTPTR_FORMAT, requested_addr));
+ fail_continue("Unable to reserve shared space at required address " INTPTR_FORMAT, requested_addr);
return rs;
}
// the reserved virtual memory is for mapping class data sharing archive
@@ -558,7 +558,7 @@
requested_addr, size, si->_read_only,
si->_allow_exec);
if (base == NULL || base != si->_base) {
- fail_continue(err_msg("Unable to map %s shared space at required address.", shared_region_name[i]));
+ fail_continue("Unable to map %s shared space at required address.", shared_region_name[i]);
return NULL;
}
#ifdef _WINDOWS
@@ -584,7 +584,7 @@
void FileMapInfo::assert_mark(bool check) {
if (!check) {
- fail_stop("Mark mismatch while restoring from shared file.", NULL);
+ fail_stop("Mark mismatch while restoring from shared file.");
}
}
@@ -709,7 +709,7 @@
void FileMapInfo::stop_sharing_and_unmap(const char* msg) {
FileMapInfo *map_info = FileMapInfo::current_info();
if (map_info) {
- map_info->fail_continue(msg);
+ map_info->fail_continue("%s", msg);
for (int i = 0; i < MetaspaceShared::n_regions; i++) {
if (map_info->_header->_space[i]._base != NULL) {
map_info->unmap_region(i);
@@ -717,6 +717,6 @@
}
}
} else if (DumpSharedSpaces) {
- fail_stop(msg, NULL);
+ fail_stop("%s", msg);
}
}
--- a/hotspot/src/share/vm/memory/filemap.hpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/memory/filemap.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -190,8 +190,8 @@
bool remap_shared_readonly_as_readwrite();
// Errors.
- static void fail_stop(const char *msg, ...);
- static void fail_continue(const char *msg, ...);
+ static void fail_stop(const char *msg, ...) ATTRIBUTE_PRINTF(1, 2);
+ static void fail_continue(const char *msg, ...) ATTRIBUTE_PRINTF(1, 2);
// Return true if given address is in the mapped shared space.
bool is_in_shared_space(const void* p) NOT_CDS_RETURN_(false);
--- a/hotspot/src/share/vm/memory/metaspace.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/memory/metaspace.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -3126,6 +3126,8 @@
if (DumpSharedSpaces) {
#if INCLUDE_CDS
+ MetaspaceShared::estimate_regions_size();
+
SharedReadOnlySize = align_size_up(SharedReadOnlySize, max_alignment);
SharedReadWriteSize = align_size_up(SharedReadWriteSize, max_alignment);
SharedMiscDataSize = align_size_up(SharedMiscDataSize, max_alignment);
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -816,6 +816,7 @@
//tty->print_cr("Preload failed: %s", class_name);
}
}
+ fclose(file);
} else {
char errmsg[JVM_MAXPATHLEN];
os::lasterror(errmsg, JVM_MAXPATHLEN);
@@ -1086,3 +1087,49 @@
}
return true;
}
+
+int MetaspaceShared::count_class(const char* classlist_file) {
+ if (classlist_file == NULL) {
+ return 0;
+ }
+ char class_name[256];
+ int class_count = 0;
+ FILE* file = fopen(classlist_file, "r");
+ if (file != NULL) {
+ while ((fgets(class_name, sizeof class_name, file)) != NULL) {
+ if (*class_name == '#') { // comment
+ continue;
+ }
+ class_count++;
+ }
+ fclose(file);
+ } else {
+ char errmsg[JVM_MAXPATHLEN];
+ os::lasterror(errmsg, JVM_MAXPATHLEN);
+ tty->print_cr("Loading classlist failed: %s", errmsg);
+ exit(1);
+ }
+
+ return class_count;
+}
+
+// the sizes are good for typical large applications that have a lot of shared
+// classes
+void MetaspaceShared::estimate_regions_size() {
+ int class_count = count_class(SharedClassListFile);
+ class_count += count_class(ExtraSharedClassListFile);
+
+ if (class_count > LargeThresholdClassCount) {
+ if (class_count < HugeThresholdClassCount) {
+ SET_ESTIMATED_SIZE(Large, ReadOnly);
+ SET_ESTIMATED_SIZE(Large, ReadWrite);
+ SET_ESTIMATED_SIZE(Large, MiscData);
+ SET_ESTIMATED_SIZE(Large, MiscCode);
+ } else {
+ SET_ESTIMATED_SIZE(Huge, ReadOnly);
+ SET_ESTIMATED_SIZE(Huge, ReadWrite);
+ SET_ESTIMATED_SIZE(Huge, MiscData);
+ SET_ESTIMATED_SIZE(Huge, MiscCode);
+ }
+ }
+}
--- a/hotspot/src/share/vm/memory/metaspaceShared.hpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -30,6 +30,19 @@
#include "utilities/exceptions.hpp"
#include "utilities/macros.hpp"
+#define LargeSharedArchiveSize (300*M)
+#define HugeSharedArchiveSize (800*M)
+#define ReadOnlyRegionPercentage 0.4
+#define ReadWriteRegionPercentage 0.55
+#define MiscDataRegionPercentage 0.03
+#define MiscCodeRegionPercentage 0.02
+#define LargeThresholdClassCount 5000
+#define HugeThresholdClassCount 40000
+
+#define SET_ESTIMATED_SIZE(type, region) \
+ Shared ##region## Size = FLAG_IS_DEFAULT(Shared ##region## Size) ? \
+ (type ## SharedArchiveSize * region ## RegionPercentage) : Shared ## region ## Size
+
class FileMapInfo;
// Class Data Sharing Support
@@ -112,5 +125,8 @@
static void link_one_shared_class(Klass* obj, TRAPS);
static void check_one_shared_class(Klass* obj);
static void link_and_cleanup_shared_classes(TRAPS);
+
+ static int count_class(const char* classlist_file);
+ static void estimate_regions_size() NOT_CDS_RETURN;
};
#endif // SHARE_VM_MEMORY_METASPACE_SHARED_HPP
--- a/hotspot/src/share/vm/memory/tenuredGeneration.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/memory/tenuredGeneration.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -53,9 +53,11 @@
// initialize performance counters
const char* gen_name = "old";
+ GenCollectorPolicy* gcp = (GenCollectorPolicy*) GenCollectedHeap::heap()->collector_policy();
// Generation Counters -- generation 1, 1 subspace
- _gen_counters = new GenerationCounters(gen_name, 1, 1, &_virtual_space);
+ _gen_counters = new GenerationCounters(gen_name, 1, 1,
+ gcp->min_old_size(), gcp->max_old_size(), &_virtual_space);
_gc_counters = new CollectorCounters("MSC", 1);
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -68,7 +68,7 @@
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#include "gc_implementation/g1/g1OopClosures.inline.hpp"
#include "gc_implementation/g1/g1RemSet.inline.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
#include "gc_implementation/parNew/parOopClosures.inline.hpp"
#include "gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp"
#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp"
--- a/hotspot/src/share/vm/oops/instanceMirrorKlass.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -42,7 +42,7 @@
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#include "gc_implementation/g1/g1OopClosures.inline.hpp"
#include "gc_implementation/g1/g1RemSet.inline.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
#include "gc_implementation/parNew/parOopClosures.inline.hpp"
#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp"
#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp"
--- a/hotspot/src/share/vm/oops/instanceRefKlass.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/oops/instanceRefKlass.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -38,7 +38,7 @@
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#include "gc_implementation/g1/g1OopClosures.inline.hpp"
#include "gc_implementation/g1/g1RemSet.inline.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
#include "gc_implementation/parNew/parOopClosures.inline.hpp"
#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp"
#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp"
--- a/hotspot/src/share/vm/oops/objArrayKlass.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -51,7 +51,7 @@
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#include "gc_implementation/g1/g1OopClosures.inline.hpp"
#include "gc_implementation/g1/g1RemSet.inline.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
+#include "gc_implementation/g1/heapRegionManager.inline.hpp"
#include "gc_implementation/parNew/parOopClosures.inline.hpp"
#include "gc_implementation/parallelScavenge/psCompactionManager.hpp"
#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp"
--- a/hotspot/src/share/vm/opto/type.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/opto/type.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -1708,8 +1708,8 @@
// Make a TypeTuple from the range of a method signature
const TypeTuple *TypeTuple::make_range(ciSignature* sig) {
ciType* return_type = sig->return_type();
- uint total_fields = TypeFunc::Parms + return_type->size();
- const Type **field_array = fields(total_fields);
+ uint arg_cnt = return_type->size();
+ const Type **field_array = fields(arg_cnt);
switch (return_type->basic_type()) {
case T_LONG:
field_array[TypeFunc::Parms] = TypeLong::LONG;
@@ -1734,26 +1734,26 @@
default:
ShouldNotReachHere();
}
- return (TypeTuple*)(new TypeTuple(total_fields,field_array))->hashcons();
+ return (TypeTuple*)(new TypeTuple(TypeFunc::Parms + arg_cnt, field_array))->hashcons();
}
// Make a TypeTuple from the domain of a method signature
const TypeTuple *TypeTuple::make_domain(ciInstanceKlass* recv, ciSignature* sig) {
- uint total_fields = TypeFunc::Parms + sig->size();
+ uint arg_cnt = sig->size();
uint pos = TypeFunc::Parms;
const Type **field_array;
if (recv != NULL) {
- total_fields++;
- field_array = fields(total_fields);
+ arg_cnt++;
+ field_array = fields(arg_cnt);
// Use get_const_type here because it respects UseUniqueSubclasses:
field_array[pos++] = get_const_type(recv)->join_speculative(TypePtr::NOTNULL);
} else {
- field_array = fields(total_fields);
+ field_array = fields(arg_cnt);
}
int i = 0;
- while (pos < total_fields) {
+ while (pos < TypeFunc::Parms + arg_cnt) {
ciType* type = sig->type_at(i);
switch (type->basic_type()) {
@@ -1780,7 +1780,8 @@
}
i++;
}
- return (TypeTuple*)(new TypeTuple(total_fields,field_array))->hashcons();
+
+ return (TypeTuple*)(new TypeTuple(TypeFunc::Parms + arg_cnt, field_array))->hashcons();
}
const TypeTuple *TypeTuple::make( uint cnt, const Type **fields ) {
@@ -1789,6 +1790,7 @@
//------------------------------fields-----------------------------------------
// Subroutine call type with space allocated for argument types
+// Memory for Control, I_O, Memory, FramePtr, and ReturnAdr is allocated implicitly
const Type **TypeTuple::fields( uint arg_cnt ) {
const Type **flds = (const Type **)(Compile::current()->type_arena()->Amalloc_4((TypeFunc::Parms+arg_cnt)*sizeof(Type*) ));
flds[TypeFunc::Control ] = Type::CONTROL;
--- a/hotspot/src/share/vm/opto/type.hpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/opto/type.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, 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
@@ -635,6 +635,7 @@
static const TypeTuple *make_domain(ciInstanceKlass* recv, ciSignature *sig);
// Subroutine call type with space allocated for argument types
+ // Memory for Control, I_O, Memory, FramePtr, and ReturnAdr is allocated implicitly
static const Type **fields( uint arg_cnt );
virtual const Type *xmeet( const Type *t ) const;
--- a/hotspot/src/share/vm/runtime/java.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/runtime/java.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -430,6 +430,8 @@
}
}
+jint volatile vm_getting_terminated = 0;
+
// Note: before_exit() can be executed only once, if more than one threads
// are trying to shutdown the VM at the same time, only one thread
// can run before_exit() and all other threads must wait.
@@ -460,6 +462,8 @@
}
}
+ OrderAccess::release_store(&vm_getting_terminated, 1);
+
// The only difference between this and Win32's _onexit procs is that
// this version is invoked before any threads get killed.
ExitProc* current = exit_procs;
--- a/hotspot/src/share/vm/services/mallocTracker.hpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/services/mallocTracker.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -171,8 +171,9 @@
// Total malloc'd memory used by arenas
size_t total_arena() const;
- inline size_t thread_count() {
- return by_type(mtThreadStack)->malloc_count();
+ inline size_t thread_count() const {
+ MallocMemorySnapshot* s = const_cast<MallocMemorySnapshot*>(this);
+ return s->by_type(mtThreadStack)->malloc_count();
}
void reset();
--- a/hotspot/src/share/vm/services/memBaseline.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/services/memBaseline.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -70,15 +70,13 @@
*/
class MallocAllocationSiteWalker : public MallocSiteWalker {
private:
- SortedLinkedList<MallocSite, compare_malloc_size, ResourceObj::ARENA>
- _malloc_sites;
+ SortedLinkedList<MallocSite, compare_malloc_size> _malloc_sites;
size_t _count;
// Entries in MallocSiteTable with size = 0 and count = 0,
// when the malloc site is not longer there.
public:
- MallocAllocationSiteWalker(Arena* arena) : _count(0), _malloc_sites(arena) {
- }
+ MallocAllocationSiteWalker() : _count(0) { }
inline size_t count() const { return _count; }
@@ -109,13 +107,12 @@
// Walk all virtual memory regions for baselining
class VirtualMemoryAllocationWalker : public VirtualMemoryWalker {
private:
- SortedLinkedList<ReservedMemoryRegion, compare_virtual_memory_base, ResourceObj::ARENA>
+ SortedLinkedList<ReservedMemoryRegion, compare_virtual_memory_base>
_virtual_memory_regions;
size_t _count;
public:
- VirtualMemoryAllocationWalker(Arena* a) : _count(0), _virtual_memory_regions(a) {
- }
+ VirtualMemoryAllocationWalker() : _count(0) { }
bool do_allocation_site(const ReservedMemoryRegion* rgn) {
if (rgn->size() >= MemBaseline::SIZE_THRESHOLD) {
@@ -136,39 +133,30 @@
bool MemBaseline::baseline_summary() {
- assert(_malloc_memory_snapshot == NULL, "Malloc baseline not yet reset");
- assert(_virtual_memory_snapshot == NULL, "Virtual baseline not yet reset");
-
- _malloc_memory_snapshot = new (arena()) MallocMemorySnapshot();
- _virtual_memory_snapshot = new (arena()) VirtualMemorySnapshot();
- if (_malloc_memory_snapshot == NULL || _virtual_memory_snapshot == NULL) {
- return false;
- }
- MallocMemorySummary::snapshot(_malloc_memory_snapshot);
- VirtualMemorySummary::snapshot(_virtual_memory_snapshot);
+ MallocMemorySummary::snapshot(&_malloc_memory_snapshot);
+ VirtualMemorySummary::snapshot(&_virtual_memory_snapshot);
return true;
}
bool MemBaseline::baseline_allocation_sites() {
- assert(arena() != NULL, "Just check");
// Malloc allocation sites
- MallocAllocationSiteWalker malloc_walker(arena());
+ MallocAllocationSiteWalker malloc_walker;
if (!MallocSiteTable::walk_malloc_site(&malloc_walker)) {
return false;
}
- _malloc_sites.set_head(malloc_walker.malloc_sites()->head());
+ _malloc_sites.move(malloc_walker.malloc_sites());
// The malloc sites are collected in size order
_malloc_sites_order = by_size;
// Virtual memory allocation sites
- VirtualMemoryAllocationWalker virtual_memory_walker(arena());
+ VirtualMemoryAllocationWalker virtual_memory_walker;
if (!VirtualMemoryTracker::walk_virtual_memory(&virtual_memory_walker)) {
return false;
}
// Virtual memory allocations are collected in call stack order
- _virtual_memory_allocations.set_head(virtual_memory_walker.virtual_memory_allocations()->head());
+ _virtual_memory_allocations.move(virtual_memory_walker.virtual_memory_allocations());
if (!aggregate_virtual_memory_allocation_sites()) {
return false;
@@ -180,11 +168,6 @@
}
bool MemBaseline::baseline(bool summaryOnly) {
- if (arena() == NULL) {
- _arena = new (std::nothrow, mtNMT) Arena(mtNMT);
- if (arena() == NULL) return false;
- }
-
reset();
_class_count = InstanceKlass::number_of_instance_classes();
@@ -211,8 +194,7 @@
}
bool MemBaseline::aggregate_virtual_memory_allocation_sites() {
- SortedLinkedList<VirtualMemoryAllocationSite, compare_allocation_site, ResourceObj::ARENA>
- allocation_sites(arena());
+ SortedLinkedList<VirtualMemoryAllocationSite, compare_allocation_site> allocation_sites;
VirtualMemoryAllocationIterator itr = virtual_memory_allocations();
const ReservedMemoryRegion* rgn;
@@ -230,12 +212,12 @@
site->commit_memory(rgn->committed_size());
}
- _virtual_memory_sites.set_head(allocation_sites.head());
+ _virtual_memory_sites.move(&allocation_sites);
return true;
}
MallocSiteIterator MemBaseline::malloc_sites(SortingOrder order) {
- assert(!_malloc_sites.is_empty(), "Detail baseline?");
+ assert(!_malloc_sites.is_empty(), "Not detail baseline");
switch(order) {
case by_size:
malloc_sites_to_size_order();
@@ -251,7 +233,7 @@
}
VirtualMemorySiteIterator MemBaseline::virtual_memory_sites(SortingOrder order) {
- assert(!_virtual_memory_sites.is_empty(), "Detail baseline?");
+ assert(!_virtual_memory_sites.is_empty(), "Not detail baseline");
switch(order) {
case by_size:
virtual_memory_sites_to_size_order();
@@ -270,8 +252,7 @@
// Sorting allocations sites in different orders
void MemBaseline::malloc_sites_to_size_order() {
if (_malloc_sites_order != by_size) {
- SortedLinkedList<MallocSite, compare_malloc_size, ResourceObj::ARENA>
- tmp(arena());
+ SortedLinkedList<MallocSite, compare_malloc_size> tmp;
// Add malloc sites to sorted linked list to sort into size order
tmp.move(&_malloc_sites);
@@ -283,8 +264,7 @@
void MemBaseline::malloc_sites_to_allocation_site_order() {
if (_malloc_sites_order != by_site) {
- SortedLinkedList<MallocSite, compare_malloc_site, ResourceObj::ARENA>
- tmp(arena());
+ SortedLinkedList<MallocSite, compare_malloc_site> tmp;
// Add malloc sites to sorted linked list to sort into site (address) order
tmp.move(&_malloc_sites);
_malloc_sites.set_head(tmp.head());
@@ -295,8 +275,7 @@
void MemBaseline::virtual_memory_sites_to_size_order() {
if (_virtual_memory_sites_order != by_size) {
- SortedLinkedList<VirtualMemoryAllocationSite, compare_virtual_memory_size, ResourceObj::ARENA>
- tmp(arena());
+ SortedLinkedList<VirtualMemoryAllocationSite, compare_virtual_memory_size> tmp;
tmp.move(&_virtual_memory_sites);
@@ -308,10 +287,9 @@
void MemBaseline::virtual_memory_sites_to_reservation_site_order() {
if (_virtual_memory_sites_order != by_size) {
- SortedLinkedList<VirtualMemoryAllocationSite, compare_virtual_memory_site, ResourceObj::ARENA>
- tmp(arena());
+ SortedLinkedList<VirtualMemoryAllocationSite, compare_virtual_memory_site> tmp;
- tmp.add(&_virtual_memory_sites);
+ tmp.move(&_virtual_memory_sites);
_virtual_memory_sites.set_head(tmp.head());
tmp.set_head(NULL);
--- a/hotspot/src/share/vm/services/memBaseline.hpp Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/src/share/vm/services/memBaseline.hpp Wed Jul 05 19:59:54 2017 +0200
@@ -61,28 +61,22 @@
};
private:
- // All baseline data is stored in this arena
- Arena* _arena;
-
// Summary information
- MallocMemorySnapshot* _malloc_memory_snapshot;
- VirtualMemorySnapshot* _virtual_memory_snapshot;
+ MallocMemorySnapshot _malloc_memory_snapshot;
+ VirtualMemorySnapshot _virtual_memory_snapshot;
size_t _class_count;
// Allocation sites information
// Malloc allocation sites
- LinkedListImpl<MallocSite, ResourceObj::ARENA>
- _malloc_sites;
+ LinkedListImpl<MallocSite> _malloc_sites;
// All virtual memory allocations
- LinkedListImpl<ReservedMemoryRegion, ResourceObj::ARENA>
- _virtual_memory_allocations;
+ LinkedListImpl<ReservedMemoryRegion> _virtual_memory_allocations;
// Virtual memory allocations by allocation sites, always in by_address
// order
- LinkedListImpl<VirtualMemoryAllocationSite, ResourceObj::ARENA>
- _virtual_memory_sites;
+ LinkedListImpl<VirtualMemoryAllocationSite> _virtual_memory_sites;
SortingOrder _malloc_sites_order;
SortingOrder _virtual_memory_sites_order;
@@ -93,30 +87,23 @@
// create a memory baseline
MemBaseline():
_baseline_type(Not_baselined),
- _class_count(0),
- _arena(NULL),
- _malloc_memory_snapshot(NULL),
- _virtual_memory_snapshot(NULL),
- _malloc_sites(NULL) {
+ _class_count(0) {
}
~MemBaseline() {
reset();
- if (_arena != NULL) {
- delete _arena;
- }
}
bool baseline(bool summaryOnly = true);
BaselineType baseline_type() const { return _baseline_type; }
- MallocMemorySnapshot* malloc_memory_snapshot() const {
- return _malloc_memory_snapshot;
+ MallocMemorySnapshot* malloc_memory_snapshot() {
+ return &_malloc_memory_snapshot;
}
- VirtualMemorySnapshot* virtual_memory_snapshot() const {
- return _virtual_memory_snapshot;
+ VirtualMemorySnapshot* virtual_memory_snapshot() {
+ return &_virtual_memory_snapshot;
}
MallocSiteIterator malloc_sites(SortingOrder order);
@@ -133,10 +120,8 @@
// memory
size_t total_reserved_memory() const {
assert(baseline_type() != Not_baselined, "Not yet baselined");
- assert(_virtual_memory_snapshot != NULL, "No virtual memory snapshot");
- assert(_malloc_memory_snapshot != NULL, "No malloc memory snapshot");
- size_t amount = _malloc_memory_snapshot->total() +
- _virtual_memory_snapshot->total_reserved();
+ size_t amount = _malloc_memory_snapshot.total() +
+ _virtual_memory_snapshot.total_reserved();
return amount;
}
@@ -144,32 +129,30 @@
// virtual memory
size_t total_committed_memory() const {
assert(baseline_type() != Not_baselined, "Not yet baselined");
- assert(_virtual_memory_snapshot != NULL,
- "Not a snapshot");
- size_t amount = _malloc_memory_snapshot->total() +
- _virtual_memory_snapshot->total_committed();
+ size_t amount = _malloc_memory_snapshot.total() +
+ _virtual_memory_snapshot.total_committed();
return amount;
}
size_t total_arena_memory() const {
assert(baseline_type() != Not_baselined, "Not yet baselined");
- assert(_malloc_memory_snapshot != NULL, "Not yet baselined");
- return _malloc_memory_snapshot->total_arena();
+ return _malloc_memory_snapshot.total_arena();
}
size_t malloc_tracking_overhead() const {
assert(baseline_type() != Not_baselined, "Not yet baselined");
- return _malloc_memory_snapshot->malloc_overhead()->size();
+ MemBaseline* bl = const_cast<MemBaseline*>(this);
+ return bl->_malloc_memory_snapshot.malloc_overhead()->size();
}
- const MallocMemory* malloc_memory(MEMFLAGS flag) const {
- assert(_malloc_memory_snapshot != NULL, "Not a snapshot");
- return _malloc_memory_snapshot->by_type(flag);
+ MallocMemory* malloc_memory(MEMFLAGS flag) {
+ assert(baseline_type() != Not_baselined, "Not yet baselined");
+ return _malloc_memory_snapshot.by_type(flag);
}
- const VirtualMemory* virtual_memory(MEMFLAGS flag) const {
- assert(_virtual_memory_snapshot != NULL, "Not a snapshot");
- return _virtual_memory_snapshot->by_type(flag);
+ VirtualMemory* virtual_memory(MEMFLAGS flag) {
+ assert(baseline_type() != Not_baselined, "Not yet baselined");
+ return _virtual_memory_snapshot.by_type(flag);
}
@@ -180,24 +163,19 @@
size_t thread_count() const {
assert(baseline_type() != Not_baselined, "Not yet baselined");
- assert(_malloc_memory_snapshot != NULL, "Baselined?");
- return _malloc_memory_snapshot->thread_count();
+ return _malloc_memory_snapshot.thread_count();
}
// reset the baseline for reuse
void reset() {
_baseline_type = Not_baselined;
- _malloc_memory_snapshot = NULL;
- _virtual_memory_snapshot = NULL;
+ _malloc_memory_snapshot.reset();
+ _virtual_memory_snapshot.reset();
_class_count = 0;
- _malloc_sites = NULL;
- _virtual_memory_sites = NULL;
- _virtual_memory_allocations = NULL;
-
- if (_arena != NULL) {
- _arena->destruct_contents();
- }
+ _malloc_sites.clear();
+ _virtual_memory_sites.clear();
+ _virtual_memory_allocations.clear();
}
private:
@@ -210,8 +188,6 @@
// Aggregate virtual memory allocation by allocation sites
bool aggregate_virtual_memory_allocation_sites();
- Arena* arena() { return _arena; }
-
// Sorting allocation sites in different orders
// Sort allocation sites in size order
void malloc_sites_to_size_order();
--- a/hotspot/test/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/test/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java Wed Jul 05 19:59:54 2017 +0200
@@ -35,7 +35,9 @@
* @summary "Tests unloading of anonymous classes."
* @library /testlibrary /testlibrary/whitebox
* @compile TestAnonymousClassUnloading.java
- * @run main ClassFileInstaller TestAnonymousClassUnloading sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller TestAnonymousClassUnloading
+ * sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-BackgroundCompilation TestAnonymousClassUnloading
*/
public class TestAnonymousClassUnloading {
--- a/hotspot/test/compiler/classUnloading/methodUnloading/TestMethodUnloading.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/test/compiler/classUnloading/methodUnloading/TestMethodUnloading.java Wed Jul 05 19:59:54 2017 +0200
@@ -36,7 +36,7 @@
* @build WorkerClass
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-BackgroundCompilation -XX:-UseCompressedOops -XX:+UseParallelGC -XX:CompileOnly=TestMethodUnloading::doWork TestMethodUnloading
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-BackgroundCompilation -XX:-UseCompressedOops -XX:CompileOnly=TestMethodUnloading::doWork TestMethodUnloading
*/
public class TestMethodUnloading {
private static final String workerClassName = "WorkerClass";
--- a/hotspot/test/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnSupportedConfig.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/test/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnSupportedConfig.java Wed Jul 05 19:59:54 2017 +0200
@@ -54,16 +54,19 @@
CommandLineOptionTest.verifyOptionValueForSameVM(optionName,
TestPrintPreciseRTMLockingStatisticsBase.DEFAULT_VALUE,
CommandLineOptionTest.UNLOCK_DIAGNOSTIC_VM_OPTIONS,
+ CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
"-XX:+UseRTMLocking");
CommandLineOptionTest.verifyOptionValueForSameVM(optionName,
TestPrintPreciseRTMLockingStatisticsBase.DEFAULT_VALUE,
CommandLineOptionTest.UNLOCK_DIAGNOSTIC_VM_OPTIONS,
+ CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
"-XX:-UseRTMLocking", prepareOptionValue("true"));
// verify that option could be turned on
CommandLineOptionTest.verifyOptionValueForSameVM(optionName, "true",
CommandLineOptionTest.UNLOCK_DIAGNOSTIC_VM_OPTIONS,
+ CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
"-XX:+UseRTMLocking", prepareOptionValue("true"));
}
--- a/hotspot/test/compiler/rtm/cli/TestUseRTMDeoptOptionOnSupportedConfig.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/test/compiler/rtm/cli/TestUseRTMDeoptOptionOnSupportedConfig.java Wed Jul 05 19:59:54 2017 +0200
@@ -63,13 +63,16 @@
// verify default value
CommandLineOptionTest.verifyOptionValueForSameVM("UseRTMDeopt",
TestUseRTMDeoptOptionOnSupportedConfig.DEFAULT_VALUE,
+ CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
"-XX:+UseRTMLocking");
// verify that option is off when UseRTMLocking is off
- CommandLineOptionTest.verifyOptionValueForSameVM("UseRTMDeopt",
- "false", "-XX:-UseRTMLocking", "-XX:+UseRTMDeopt");
+ CommandLineOptionTest.verifyOptionValueForSameVM("UseRTMDeopt", "false",
+ CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
+ "-XX:-UseRTMLocking", "-XX:+UseRTMDeopt");
// verify that option could be turned on
- CommandLineOptionTest.verifyOptionValueForSameVM("UseRTMDeopt",
- "true", "-XX:+UseRTMLocking", "-XX:+UseRTMDeopt");
+ CommandLineOptionTest.verifyOptionValueForSameVM("UseRTMDeopt", "true",
+ CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
+ "-XX:+UseRTMLocking", "-XX:+UseRTMDeopt");
}
public static void main(String args[]) throws Throwable {
--- a/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnSupportedConfig.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnSupportedConfig.java Wed Jul 05 19:59:54 2017 +0200
@@ -59,24 +59,31 @@
new String[]{
RTMGenericCommandLineOptionTest.RTM_INSTR_ERROR,
unrecongnizedOption
- }, ExitCode.OK, "-XX:+UseRTMLocking"
+ }, ExitCode.OK,
+ CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
+ "-XX:+UseRTMLocking"
);
CommandLineOptionTest.verifySameJVMStartup(null,
new String[]{
RTMGenericCommandLineOptionTest.RTM_INSTR_ERROR,
unrecongnizedOption
- }, ExitCode.OK, "-XX:-UseRTMLocking"
+ }, ExitCode.OK,
+ CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
+ "-XX:-UseRTMLocking"
);
// verify that UseRTMLocking is of by default
CommandLineOptionTest.verifyOptionValueForSameVM("UseRTMLocking",
- TestUseRTMLockingOptionOnSupportedConfig.DEFAULT_VALUE);
+ TestUseRTMLockingOptionOnSupportedConfig.DEFAULT_VALUE,
+ CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS);
// verify that we can change UseRTMLocking value
CommandLineOptionTest.verifyOptionValueForSameVM("UseRTMLocking",
TestUseRTMLockingOptionOnSupportedConfig.DEFAULT_VALUE,
+ CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
"-XX:-UseRTMLocking");
CommandLineOptionTest.verifyOptionValueForSameVM("UseRTMLocking",
- "true", "-XX:+UseRTMLocking");
+ "true", CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
+ "-XX:+UseRTMLocking");
}
public static void main(String args[]) throws Throwable {
--- a/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionWithBiasedLocking.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionWithBiasedLocking.java Wed Jul 05 19:59:54 2017 +0200
@@ -54,18 +54,22 @@
// verify that we will not get a warning
CommandLineOptionTest.verifySameJVMStartup(null,
new String[] { warningMessage }, ExitCode.OK,
+ CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
"-XX:+UseRTMLocking", "-XX:-UseBiasedLocking");
// verify that we will get a warning
CommandLineOptionTest.verifySameJVMStartup(
new String[] { warningMessage }, null, ExitCode.OK,
+ CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
"-XX:+UseRTMLocking", "-XX:+UseBiasedLocking");
// verify that UseBiasedLocking is false when we use rtm locking
CommandLineOptionTest.verifyOptionValueForSameVM("UseBiasedLocking",
- "false", "-XX:+UseRTMLocking");
+ "false", CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
+ "-XX:+UseRTMLocking");
// verify that we can't turn on biased locking when
// using rtm locking
CommandLineOptionTest.verifyOptionValueForSameVM("UseBiasedLocking",
- "false", "-XX:+UseRTMLocking", "-XX:+UseBiasedLocking");
+ "false", CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
+ "-XX:+UseRTMLocking", "-XX:+UseBiasedLocking");
}
public static void main(String args[]) throws Throwable {
--- a/hotspot/test/gc/g1/TestHumongousShrinkHeap.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/test/gc/g1/TestHumongousShrinkHeap.java Wed Jul 05 19:59:54 2017 +0200
@@ -22,9 +22,8 @@
*/
/**
- * @ignore 8041506, 8041946, 8042051
* @test TestHumongousShrinkHeap
- * @bug 8036025
+ * @bug 8036025 8056043
* @summary Verify that heap shrinks after GC in the presence of fragmentation due to humongous objects
* @library /testlibrary
* @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=50 -XX:+UseG1GC -XX:G1HeapRegionSize=1M -verbose:gc TestHumongousShrinkHeap
--- a/hotspot/test/gc/g1/TestStringDeduplicationTools.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/test/gc/g1/TestStringDeduplicationTools.java Wed Jul 05 19:59:54 2017 +0200
@@ -129,8 +129,19 @@
return list;
}
+ /**
+ * Verifies that the given list contains expected number of unique strings.
+ * It's possible that deduplication hasn't completed yet, so the method
+ * will perform several attempts to check with a little pause between.
+ * The method throws RuntimeException to signal that verification failed.
+ *
+ * @param list strings to check
+ * @param uniqueExpected expected number of unique strings
+ * @throws RuntimeException if check fails
+ */
private static void verifyStrings(ArrayList<String> list, int uniqueExpected) {
- for (;;) {
+ boolean passed = false;
+ for (int attempts = 0; attempts < 10; attempts++) {
// Check number of deduplicated strings
ArrayList<Object> unique = new ArrayList<Object>(uniqueExpected);
for (String string: list) {
@@ -153,11 +164,11 @@
", uniqueExpected=" + uniqueExpected);
if (unique.size() == uniqueExpected) {
- System.out.println("Deduplication completed");
+ System.out.println("Deduplication completed (as fast as " + attempts + " iterations)");
+ passed = true;
break;
} else {
System.out.println("Deduplication not completed, waiting...");
-
// Give the deduplication thread time to complete
try {
Thread.sleep(1000);
@@ -166,6 +177,9 @@
}
}
}
+ if (!passed) {
+ throw new RuntimeException("String verification failed");
+ }
}
private static OutputAnalyzer runTest(String... extraArgs) throws Exception {
@@ -247,14 +261,20 @@
forceDeduplication(ageThreshold, FullGC);
// Wait for deduplication to occur
- while (getValue(dupString1) != getValue(baseString)) {
+ for (int attempts = 0; attempts < 10; attempts++) {
+ if (getValue(dupString1) == getValue(baseString)) {
+ break;
+ }
System.out.println("Waiting...");
try {
- Thread.sleep(100);
+ Thread.sleep(1000);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
+ if (getValue(dupString1) != getValue(baseString)) {
+ throw new RuntimeException("Deduplication has not occurred");
+ }
// Create a new duplicate of baseString
StringBuilder sb2 = new StringBuilder(baseString);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/whitebox/TestWBGC.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014, 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 TestWBGC
+ * @bug 8055098
+ * @summary Test verify that WB methods isObjectInOldGen and youngGC works correctly.
+ * @library /testlibrary /testlibrary/whitebox
+ * @build TestWBGC
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run driver TestWBGC
+ */
+import com.oracle.java.testlibrary.*;
+import sun.hotspot.WhiteBox;
+
+public class TestWBGC {
+
+ public static void main(String args[]) throws Exception {
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+ true,
+ "-Xbootclasspath/a:.",
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+WhiteBoxAPI",
+ "-XX:MaxTenuringThreshold=1",
+ "-XX:+PrintGC",
+ GCYoungTest.class.getName());
+
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ System.out.println(output.getStdout());
+ output.shouldHaveExitValue(0);
+ output.shouldContain("WhiteBox Initiated Young GC");
+ output.shouldNotContain("Full");
+ // To be sure that we don't provoke Full GC additionaly to young
+ }
+
+ public static class GCYoungTest {
+ static WhiteBox wb = WhiteBox.getWhiteBox();
+ public static Object obj;
+
+ public static void main(String args[]) {
+ obj = new Object();
+ Asserts.assertFalse(wb.isObjectInOldGen(obj));
+ wb.youngGC();
+ wb.youngGC();
+ // 2 young GC is needed to promote object into OldGen
+ Asserts.assertTrue(wb.isObjectInOldGen(obj));
+ }
+ }
+}
--- a/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java Wed Jul 05 19:59:54 2017 +0200
@@ -26,7 +26,6 @@
* @bug 8024927
* @summary Testing address of compressed class pointer space as best as possible.
* @library /testlibrary
- * @ignore 8055164
*/
import com.oracle.java.testlibrary.*;
@@ -89,7 +88,6 @@
"-version");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("HeapBaseMinAddress must be at least");
- output.shouldContain("HotSpot");
output.shouldHaveExitValue(0);
}
--- a/hotspot/test/runtime/NMT/CommandLineEmptyArgument.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/test/runtime/NMT/CommandLineEmptyArgument.java Wed Jul 05 19:59:54 2017 +0200
@@ -26,7 +26,6 @@
* @key nmt
* @summary Empty argument to NMT should result in an informative error message
* @library /testlibrary
- * @ignore 8055051
*/
import com.oracle.java.testlibrary.*;
--- a/hotspot/test/runtime/NMT/JcmdDetailDiff.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/test/runtime/NMT/JcmdDetailDiff.java Wed Jul 05 19:59:54 2017 +0200
@@ -62,21 +62,18 @@
output = new OutputAnalyzer(pb.start());
output.shouldContain("Test (reserved=256KB +256KB, committed=0KB)");
- output.shouldContain("WB_NMTReserveMemory");
wb.NMTCommitMemory(addr, commitSize);
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail.diff", "scale=KB"});
output = new OutputAnalyzer(pb.start());
output.shouldContain("Test (reserved=256KB +256KB, committed=128KB +128KB)");
- output.shouldContain("WB_NMTReserveMemory");
wb.NMTUncommitMemory(addr, commitSize);
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail.diff", "scale=KB"});
output = new OutputAnalyzer(pb.start());
output.shouldContain("Test (reserved=256KB +256KB, committed=0KB)");
- output.shouldContain("WB_NMTReserveMemory");
wb.NMTReleaseMemory(addr, reserveSize);
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail.diff", "scale=KB"});
--- a/hotspot/test/runtime/NMT/MallocSiteHashOverflow.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/test/runtime/NMT/MallocSiteHashOverflow.java Wed Jul 05 19:59:54 2017 +0200
@@ -22,10 +22,9 @@
*/
/*
- * @key stress
* @test
* @summary Test corner case that overflows malloc site hashtable bucket
- * @key nmt jcmd
+ * @key nmt jcmd stress
* @library /testlibrary /testlibrary/whitebox
* @ignore - This test is disabled since it will stress NMT and timeout during normal testing
* @build MallocSiteHashOverflow
--- a/hotspot/test/runtime/NMT/MallocStressTest.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/test/runtime/NMT/MallocStressTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -22,10 +22,9 @@
*/
/*
- * @key stress
* @test
* @summary Stress test for malloc tracking
- * @key nmt jcmd
+ * @key nmt jcmd stress
* @library /testlibrary /testlibrary/whitebox
* @build MallocStressTest
* @ignore - This test is disabled since it will stress NMT and timeout during normal testing
--- a/hotspot/test/runtime/NMT/NMTWithCDS.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/test/runtime/NMT/NMTWithCDS.java Wed Jul 05 19:59:54 2017 +0200
@@ -34,14 +34,15 @@
public static void main(String[] args) throws Exception {
ProcessBuilder pb;
- pb = ProcessTools.createJavaProcessBuilder("-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump");
+ pb = ProcessTools.createJavaProcessBuilder(
+ "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
try {
output.shouldContain("Loading classes to share");
output.shouldHaveExitValue(0);
pb = ProcessTools.createJavaProcessBuilder(
- "-XX:NativeMemoryTracking=detail", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:on", "-version");
+ "-XX:+UnlockDiagnosticVMOptions", "-XX:NativeMemoryTracking=detail", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:on", "-version");
output = new OutputAnalyzer(pb.start());
output.shouldContain("sharing");
output.shouldHaveExitValue(0);
--- a/hotspot/test/runtime/NMT/VirtualAllocCommitUncommitRecommit.java Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/test/runtime/NMT/VirtualAllocCommitUncommitRecommit.java Wed Jul 05 19:59:54 2017 +0200
@@ -26,7 +26,6 @@
* @summary Test reserve/commit/uncommit/release of virtual memory and that we track it correctly
* @key nmt jcmd
* @library /testlibrary /testlibrary/whitebox
- * @ignore
* @build VirtualAllocCommitUncommitRecommit
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail VirtualAllocCommitUncommitRecommit
@@ -43,8 +42,8 @@
public static void main(String args[]) throws Exception {
OutputAnalyzer output;
- long commitSize = 4 * 1024; // 4KB
- long reserveSize = 1024 * 1024; // 1024KB
+ long commitSize = 128 * 1024; // 128KB
+ long reserveSize = 4 * 1024 * 1024; // 4096KB
long addr;
String pid = Integer.toString(ProcessTools.getProcessId());
@@ -63,11 +62,11 @@
"VM.native_memory", "detail" });
output = new OutputAnalyzer(pb.start());
- output.shouldContain("Test (reserved=1024KB, committed=0KB)");
+ output.shouldContain("Test (reserved=4096KB, committed=0KB)");
if (has_nmt_detail) {
output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*"
+ Long.toHexString(addr + reserveSize)
- + "\\] reserved 1024KB for Test");
+ + "\\] reserved 4096KB for Test");
}
long addrA = addr;
@@ -84,24 +83,24 @@
wb.NMTCommitMemory(addrD, commitSize);
output = new OutputAnalyzer(pb.start());
- output.shouldContain("Test (reserved=1024KB, committed=16KB)");
+ output.shouldContain("Test (reserved=4096KB, committed=512KB)");
if (has_nmt_detail) {
output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*"
+ Long.toHexString(addr + reserveSize)
- + "\\] reserved 1024KB for Test");
+ + "\\] reserved 4096KB for Test");
}
// uncommit BC
wb.NMTUncommitMemory(addrB, commitSize);
wb.NMTUncommitMemory(addrC, commitSize);
output = new OutputAnalyzer(pb.start());
- output.shouldContain("Test (reserved=1024KB, committed=8KB)");
+ output.shouldContain("Test (reserved=4096KB, committed=256KB)");
if (has_nmt_detail) {
output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*"
+ Long.toHexString(addr + reserveSize)
- + "\\] reserved 1024KB for Test");
+ + "\\] reserved 4096KB for Test");
}
// commit EF
@@ -109,22 +108,22 @@
wb.NMTCommitMemory(addrF, commitSize);
output = new OutputAnalyzer(pb.start());
- output.shouldContain("Test (reserved=1024KB, committed=16KB)");
+ output.shouldContain("Test (reserved=4096KB, committed=512KB)");
if (has_nmt_detail) {
output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*"
+ Long.toHexString(addr + reserveSize)
- + "\\] reserved 1024KB for Test");
+ + "\\] reserved 4096KB for Test");
}
// uncommit A
wb.NMTUncommitMemory(addrA, commitSize);
output = new OutputAnalyzer(pb.start());
- output.shouldContain("Test (reserved=1024KB, committed=12KB)");
+ output.shouldContain("Test (reserved=4096KB, committed=384KB)");
if (has_nmt_detail) {
output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*"
+ Long.toHexString(addr + reserveSize)
- + "\\] reserved 1024KB for Test");
+ + "\\] reserved 4096KB for Test");
}
// commit ABC
@@ -133,11 +132,11 @@
wb.NMTCommitMemory(addrC, commitSize);
output = new OutputAnalyzer(pb.start());
- output.shouldContain("Test (reserved=1024KB, committed=24KB)");
+ output.shouldContain("Test (reserved=4096KB, committed=768KB)");
if (has_nmt_detail) {
output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*"
+ Long.toHexString(addr + reserveSize)
- + "\\] reserved 1024KB for Test");
+ + "\\] reserved 4096KB for Test");
}
// uncommit ABCDEF
@@ -149,11 +148,11 @@
wb.NMTUncommitMemory(addrF, commitSize);
output = new OutputAnalyzer(pb.start());
- output.shouldContain("Test (reserved=1024KB, committed=0KB)");
+ output.shouldContain("Test (reserved=4096KB, committed=0KB)");
if (has_nmt_detail) {
output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*"
+ Long.toHexString(addr + reserveSize)
- + "\\] reserved 1024KB for Test");
+ + "\\] reserved 4096KB for Test");
}
// release
@@ -161,6 +160,6 @@
output = new OutputAnalyzer(pb.start());
output.shouldNotContain("Test (reserved=");
output.shouldNotMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*"
- + Long.toHexString(addr + reserveSize) + "\\] reserved");
+ + Long.toHexString(addr + reserveSize) + "\\] reserved 4096KB for Test");
}
}
--- a/hotspot/test/runtime/jsig/Test8017498.sh Thu Sep 04 13:26:26 2014 -0700
+++ b/hotspot/test/runtime/jsig/Test8017498.sh Wed Jul 05 19:59:54 2017 +0200
@@ -31,15 +31,14 @@
## @bug 8022301
## @bug 8025519
## @summary sigaction(sig) results in process hang/timed-out if sig is much greater than SIGRTMAX
-## @ignore 8041727
## @run shell/timeout=60 Test8017498.sh
##
-if [ "${TESTSRC}" = "" ]
-then
- TESTSRC=${PWD}
+if [ -z "${TESTSRC}" ]; then
+ TESTSRC="${PWD}"
echo "TESTSRC not set. Using "${TESTSRC}" as default"
fi
+
echo "TESTSRC=${TESTSRC}"
## Adding common setup Variables for running shell tests.
. ${TESTSRC}/../../test_env.sh
@@ -52,13 +51,13 @@
Linux)
echo "Testing on Linux"
gcc_cmd=`which gcc`
- if [ "x$gcc_cmd" == "x" ]; then
+ if [ -z "$gcc_cmd" ]; then
echo "WARNING: gcc not found. Cannot execute test." 2>&1
exit 0;
fi
MY_LD_PRELOAD=${TESTJAVA}${FS}jre${FS}lib${FS}${VM_CPU}${FS}libjsig.so
- if [ "$VM_BITS" == "32" ] && [ "$VM_CPU" != "arm" ] && [ "$VM_CPU" != "ppc" ]; then
- EXTRA_CFLAG=-m32
+ if [ "$VM_BITS" = "32" ] && [ "$VM_CPU" != "arm" ] && [ "$VM_CPU" != "ppc" ]; then
+ EXTRA_CFLAG=-m32
fi
echo MY_LD_PRELOAD = ${MY_LD_PRELOAD}
;;
@@ -70,7 +69,7 @@
THIS_DIR=.
-cp ${TESTSRC}${FS}*.java ${THIS_DIR}
+cp "${TESTSRC}${FS}"*.java "${THIS_DIR}"
${COMPILEJAVA}${FS}bin${FS}javac *.java
$gcc_cmd -DLINUX -fPIC -shared \
@@ -80,16 +79,19 @@
-I${COMPILEJAVA}${FS}include${FS}linux \
${TESTSRC}${FS}TestJNI.c
+if [ $? -ne 0 ] ; then
+ echo "Compile failed, Ignoring failed compilation and forcing the test to pass"
+ exit 0
+fi
+
# run the java test in the background
cmd="LD_PRELOAD=$MY_LD_PRELOAD \
${TESTJAVA}${FS}bin${FS}java \
-Djava.library.path=. -server TestJNI 100"
-echo "$cmd > test.out 2>&1"
-eval $cmd > test.out 2>&1
+echo "$cmd > test.out"
+eval $cmd > test.out
-grep "old handler" test.out > ${NULL}
-if [ $? = 0 ]
-then
+if grep "old handler" test.out > ${NULL}; then
echo "Test Passed"
exit 0
fi
--- a/jdk/.hgtags Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/.hgtags Wed Jul 05 19:59:54 2017 +0200
@@ -271,3 +271,4 @@
dde9f5cfde5f46e62ceb5fab81151578e5277aef jdk9-b26
f0870554049807d3392bd7976ab114f7f2b7bafa jdk9-b27
1828f73b35cfe35e460e41fd6e087ab1f83e0621 jdk9-b28
+2da27e8e2c865e154f0c2eb9009f011a44649b11 jdk9-b29
--- a/jdk/make/CreateJars.gmk Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/make/CreateJars.gmk Wed Jul 05 19:59:54 2017 +0200
@@ -76,13 +76,24 @@
iw ja ko lt lv mk ms mt nl no pl pt ro ru sk sl sq sr sv \
th tr uk vi zh
-LOCALEDATA_INCLUDES := $(addprefix sun/text/resources/, $(LOCALEDATA_INCLUDE_LOCALES)) \
+LOCALEDATA_INCLUDES := sun/util/resources/provider/NonEnLocaleDataMetaInfo.class
+LOCALEDATA_INCLUDES += $(addprefix sun/text/resources/, $(LOCALEDATA_INCLUDE_LOCALES)) \
$(addprefix sun/util/resources/, $(LOCALEDATA_INCLUDE_LOCALES))
-$(eval $(call SetupArchive,BUILD_LOCALEDATA_JAR, , \
- SRCS := $(JDK_OUTPUTDIR)/modules/jdk.localedata, \
+LOCALEDATA_SERVICES_DIR := $(IMAGES_OUTPUTDIR)/localemetainfo
+
+LOCALEDATA_METAINF_SERVICES := $(LOCALEDATA_SERVICES_DIR)/META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo
+
+$(LOCALEDATA_METAINF_SERVICES): $(JDK_TOPDIR)/src/jdk.localedata/META-INF/localedata-services/sun.util.locale.provider.LocaleDataMetaInfo
+ $(install-file)
+
+$(eval $(call SetupArchive,BUILD_LOCALEDATA_JAR, \
+ $(LOCALEDATA_METAINF_SERVICES), \
+ SRCS := $(JDK_OUTPUTDIR)/modules/jdk.localedata \
+ $(LOCALEDATA_SERVICES_DIR), \
SUFFIXES := .class _dict _th, \
INCLUDES := $(LOCALEDATA_INCLUDES), \
+ EXTRA_FILES := META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo, \
JAR := $(IMAGES_OUTPUTDIR)/lib/ext/localedata.jar, \
SKIP_METAINF := true))
@@ -210,6 +221,8 @@
sun/tools/tree \
sun/tools/util \
sun/util/cldr/CLDRLocaleDataMetaInfo.class \
+ sun/util/resources/provider/NonEnLocaleDataMetaInfo.class \
+ META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo \
sun/util/resources/cldr \
$(LOCALEDATA_INCLUDES) \
com/oracle/jrockit/jfr \
@@ -429,13 +442,23 @@
CLDRDATA_JAR_DST := $(IMAGES_OUTPUTDIR)/lib/ext/cldrdata.jar
-$(eval $(call SetupArchive,BUILD_CLDRDATA_JAR, , \
+CLDR_SERVICES_DIR := $(IMAGES_OUTPUTDIR)/cldrmetainfo
+
+CLDR_METAINF_SERVICES := $(CLDR_SERVICES_DIR)/META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo
+
+$(CLDR_METAINF_SERVICES): $(JDK_TOPDIR)/src/jdk.localedata/META-INF/cldrdata-services/sun.util.locale.provider.LocaleDataMetaInfo
+ $(install-file)
+
+$(eval $(call SetupArchive,BUILD_CLDRDATA_JAR, \
+ $(CLDR_METAINF_SERVICES), \
SRCS := $(JDK_OUTPUTDIR)/modules/jdk.localedata \
- $(JDK_OUTPUTDIR)/modules/java.base, \
+ $(JDK_OUTPUTDIR)/modules/java.base \
+ $(CLDR_SERVICES_DIR), \
SUFFIXES := .class, \
INCLUDES := sun/text/resources/cldr \
sun/util/cldr/CLDRLocaleDataMetaInfo.class \
sun/util/resources/cldr, \
+ EXTRA_FILES := META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo, \
JAR := $(CLDRDATA_JAR_DST), \
EXTRA_MANIFEST_ATTR := CLDR-Version: $(CLDRVERSION), \
SKIP_METAINF := true))
--- a/jdk/make/copy/Copy-java.desktop.gmk Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/make/copy/Copy-java.desktop.gmk Wed Jul 05 19:59:54 2017 +0200
@@ -43,25 +43,6 @@
################################################################################
-ICCPROFILE_DEST_DIR := $(LIB_DST_DIR)/cmm
-
-ifdef OPENJDK
- ICCPROFILE_SRC_DIR := $(JDK_TOPDIR)/src/java.desktop/share/conf/cmm/lcms
-else
- ICCPROFILE_SRC_DIR := $(JDK_TOPDIR)/src/closed/java.desktop/share/conf/cmm/kcms
-endif
-
-ICCPROFILE_SRCS := $(wildcard $(ICCPROFILE_SRC_DIR)/*.pf)
-ICCPROFILE_TARGET_FILES := $(subst $(ICCPROFILE_SRC_DIR),$(ICCPROFILE_DEST_DIR),$(ICCPROFILE_SRCS))
-
-$(ICCPROFILE_DEST_DIR)%.pf: $(ICCPROFILE_SRC_DIR)%.pf
- $(call install-file)
- $(CHMOD) 444 $@
-
-DESKTOP_CONF_FILES += $(ICCPROFILE_TARGET_FILES)
-
-################################################################################
-
ifneq ($(FREETYPE_BUNDLE_LIB_PATH), )
# We need to bundle the freetype library, so it will be available at runtime as well as link time.
#
--- a/jdk/make/data/currency/CurrencyData.properties Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/make/data/currency/CurrencyData.properties Wed Jul 05 19:59:54 2017 +0200
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2000, 2014, 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,7 +28,7 @@
# Version of the currency code information in this class.
# It is a serial number that accompanies with each amendment.
-dataVersion=156
+dataVersion=159
# List of all valid ISO 4217 currency codes.
# To ensure compatibility, do not remove codes.
@@ -332,7 +332,7 @@
# LIECHTENSTEIN
LI=CHF
# LITHUANIA
-LT=LTL
+LT=LTL;2014-12-31-22-00-00;EUR
# LUXEMBOURG
LU=EUR
# MACAU
--- a/jdk/make/gensrc/GensrcLocaleDataMetaInfo.gmk Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/make/gensrc/GensrcLocaleDataMetaInfo.gmk Wed Jul 05 19:59:54 2017 +0200
@@ -58,7 +58,14 @@
# Locales that don't have any resource files should be included here.
ALL_NON_EN_LOCALES := ja-JP-JP nb-NO nn-NO th-TH-TH
-SED_ARGS := -e 's|$(HASH)warn This file is preprocessed before being compiled|// -- This file was mechanically generated: Do not edit! -- //|g'
+SED_ENARGS := -e 's|$(HASH)warn This file is preprocessed before being compiled|// -- This file was mechanically generated: Do not edit! -- //|g'
+SED_NONENARGS := $(SED_ENARGS)
+
+# Fill in the languages and package names
+SED_ENARGS += -e 's/$(HASH)Lang$(HASH)/En/' \
+ -e 's/$(HASH)Package$(HASH)/sun.util.locale.provider/'
+SED_NONENARGS += -e 's/$(HASH)Lang$(HASH)/NonEn/' \
+ -e 's/$(HASH)Package$(HASH)/sun.util.resources.provider/'
# This macro creates a sed expression that substitues for example:
# #FormatData_ENLocales# with: en% locales.
@@ -78,8 +85,8 @@
ALL_NON_EN_LOCALES += $$($1_NON_EN_LOCALES)
# Don't sed in a space if there are no locales.
- SED_ARGS += -e 's/$$(HASH)$1_ENLocales$$(HASH)/$$(if $$($1_EN_LOCALES),$$(SPACE)$$($1_EN_LOCALES),)/g'
- SED_ARGS += -e 's/$$(HASH)$1_NonENLocales$$(HASH)/$$(if $$($1_NON_EN_LOCALES),$$(SPACE)$$($1_NON_EN_LOCALES),)/g'
+ SED_ENARGS += -e 's/$$(HASH)$1_Locales$$(HASH)/$$(if $$($1_EN_LOCALES),$$(SPACE)$$($1_EN_LOCALES),)/g'
+ SED_NONENARGS += -e 's/$$(HASH)$1_Locales$$(HASH)/$$(if $$($1_NON_EN_LOCALES),$$(SPACE)$$($1_NON_EN_LOCALES),)/g'
endef
#sun.text.resources.FormatData
@@ -106,17 +113,25 @@
#sun.util.resources.CalendarData
$(eval $(call CaptureLocale,CalendarData))
-SED_ARGS += -e 's/$(HASH)AvailableLocales_ENLocales$(HASH)/$(sort $(ALL_EN_LOCALES))/g'
-SED_ARGS += -e 's/$(HASH)AvailableLocales_NonENLocales$(HASH)/$(sort $(ALL_NON_EN_LOCALES))/g'
+SED_ENARGS += -e 's/$(HASH)AvailableLocales_Locales$(HASH)/$(sort $(ALL_EN_LOCALES))/g'
+SED_NONENARGS += -e 's/$(HASH)AvailableLocales_Locales$(HASH)/$(sort $(ALL_NON_EN_LOCALES))/g'
-$(JDK_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/LocaleDataMetaInfo.java: \
+$(JDK_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/EnLocaleDataMetaInfo.java: \
$(JDK_TOPDIR)/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template
$(MKDIR) -p $(@D)
- $(ECHO) Creating sun/util/LocaleDataMetaInfo.java from $(words $(LOCALE_RESOURCES)) found resources.
+ $(ECHO) Creating sun/util/locale/provider/EnLocaleDataMetaInfo.java from $(words $(LOCALE_RESOURCES)) found resources.
$(PRINTF) "PREV_LOCALE_RESOURCES:=$(LOCALE_RESOURCES)" > $(JDK_OUTPUTDIR)/gensrc/_the.locale_resources
- $(SED) $(SED_ARGS) $< > $@
+ $(SED) $(SED_ENARGS) $< > $@
-GENSRC_LOCALEDATAMETAINFO := $(JDK_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/LocaleDataMetaInfo.java
+$(JDK_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonEnLocaleDataMetaInfo.java: \
+ $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template
+ $(MKDIR) -p $(@D)
+ $(ECHO) Creating sun/util/resources/provider/NonEnLocaleDataMetaInfo.java from $(words $(LOCALE_RESOURCES)) found resources.
+ $(PRINTF) "PREV_LOCALE_RESOURCES:=$(LOCALE_RESOURCES)" > $(JDK_OUTPUTDIR)/gensrc/_the.locale_resources
+ $(SED) $(SED_NONENARGS) $< > $@
+
+GENSRC_LOCALEDATAMETAINFO := $(JDK_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/EnLocaleDataMetaInfo.java \
+ $(JDK_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonEnLocaleDataMetaInfo.java
################################################################################
--- a/jdk/make/profile-includes.txt Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/make/profile-includes.txt Wed Jul 05 19:59:54 2017 +0200
@@ -168,11 +168,6 @@
$(OPENJDK_TARGET_CPU_LEGACY_LIB)/$(LIBRARY_PREFIX)t2k$(SHARED_LIBRARY_SUFFIX) \
$(OPENJDK_TARGET_CPU_LEGACY_LIB)/$(LIBRARY_PREFIX)unpack$(SHARED_LIBRARY_SUFFIX) \
charsets.jar \
- cmm/CIEXYZ.pf \
- cmm/GRAY.pf \
- cmm/LINEAR_RGB.pf \
- cmm/PYCC.pf \
- cmm/sRGB.pf \
ext/cldrdata.jar \
ext/dnsns.jar \
ext/nashorn.jar \
--- a/jdk/make/src/classes/build/tools/cldrconverter/CLDRConverter.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/make/src/classes/build/tools/cldrconverter/CLDRConverter.java Wed Jul 05 19:59:54 2017 +0200
@@ -431,7 +431,7 @@
allLocales.addAll(metaInfo.get("LocaleNames"));
allLocales.addAll(metaInfo.get("CalendarData"));
allLocales.addAll(metaInfo.get("FormatData"));
- metaInfo.put("All", allLocales);
+ metaInfo.put("AvailableLocales", allLocales);
}
bundleGenerator.generateMetaInfo(metaInfo);
--- a/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java Wed Jul 05 19:59:54 2017 +0200
@@ -159,8 +159,10 @@
out.println(CopyrightHeaders.getOpenJDKCopyright());
out.println("package sun.util.cldr;\n\n"
- + "import java.util.ListResourceBundle;\n");
- out.printf("public class %s extends ListResourceBundle {\n", METAINFO_CLASS);
+ + "import java.util.ListResourceBundle;\n"
+ + "import sun.util.locale.provider.LocaleProviderAdapter;\n"
+ + "import sun.util.locale.provider.LocaleDataMetaInfo;\n");
+ out.printf("public class %s extends ListResourceBundle implements LocaleDataMetaInfo {\n", METAINFO_CLASS);
out.println(" @Override\n" +
" protected final Object[][] getContents() {\n" +
" final Object[][] data = new Object[][] {");
@@ -168,7 +170,15 @@
out.printf(" { \"%s\",\n", key);
out.printf(" \"%s\" },\n", toLocaleList(metaInfo.get(key)));
}
- out.println(" };\n return data;\n }\n}");
+ out.println(" };\n return data;\n }\n\n");
+
+ out.println(" public LocaleProviderAdapter.Type getType() {\n" +
+ " return LocaleProviderAdapter.Type.CLDR;\n" +
+ " }\n\n");
+
+ out.println(" public String availableLanguageTags(String category) {\n" +
+ " return getString(category);\n" +
+ " };\n}");
}
}
--- a/jdk/src/demo/share/java2d/J2DBench/Makefile Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/demo/share/java2d/J2DBench/Makefile Wed Jul 05 19:59:54 2017 +0200
@@ -72,6 +72,7 @@
J2DBENCH_RESOURCES = \
$(CLASSES)/j2dbench/tests/iio/images \
+ $(CLASSES)/j2dbench/tests/cmm/images \
$(CLASSES)/j2dbench/tests/text/textdata
SCM_DIRs = .hg .svn CVS RCS SCCS Codemgr_wsdata deleted_files
@@ -101,6 +102,10 @@
cp -r $< $@
cd $@ && rm -rf $(SCM_DIRs)
+$(CLASSES)/j2dbench/tests/cmm/images: $(RESOURCES)/cmm_images
+ cp -r $< $@
+ cd $@ && rm -rf $(SCM_DIRs)
+
$(CLASSES)/j2dbench.manifest:
echo "Main-Class: j2dbench.J2DBench" > $@
@@ -115,7 +120,7 @@
mkdirs: $(DIST) $(CLASSES)
$(CLASSES)/j2dbench/%.class: $(SOURCEPATH)/j2dbench/%.java
- javac -source 1.2 -target 1.2 -d $(CLASSES) -sourcepath $(SOURCEPATH) $<
+ javac -g:none -source 1.6 -target 1.6 -d $(CLASSES) -sourcepath $(SOURCEPATH) $<
clean:
rm -rf $(CLASSES)
--- a/jdk/src/demo/share/java2d/J2DBench/README Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/demo/share/java2d/J2DBench/README Wed Jul 05 19:59:54 2017 +0200
@@ -19,10 +19,9 @@
Minimum requirements
-----------------------------------------------------------------------
-The benchmark requires at least jdk1.4 to compile and
-at least jdk1.2** to run.
-
-** Note: the goal is to make the benchmark run on 1.1.x as well.
+The benchmark requires at least jdk1.4 to compile and run. Note that
+source/target is set to 1.6 in the makefile and build.xml, because of
+support in jdk 9 compiler.
-----------------------------------------------------------------------
How To Compile
@@ -125,7 +124,7 @@
After the options file is created, start J2DBench in batch mode to run
the benchmarks for the default pipeline:
-#> java -jar dest/J2DBench.jar -batch -loadopts options/default.opt \
+#> java -jar dist/J2DBench.jar -batch -loadopts options/default.opt \
-saveres default.res -title "Rendering - Default ppl" \
-desc "Rendering tests with the default pipeline"
@@ -136,13 +135,13 @@
"Run Tests" in the J2DBench dialog)
Now run the benchmark with opengl pipeline:
-#> java -Dsun.java2d.opengl=True -jar dest/J2DBench.jar -batch \
+#> java -Dsun.java2d.opengl=True -jar dist/J2DBench.jar -batch \
-loadopts options/default.opt \
-saveres opengl.res -title "Rendering - OpenGL" \
-desc "Rendering tests with OpenGL pipeline"
Now let's analyze the results using J2DAnalyzer:
-#> java -jar dest/J2DAnalyzer.jar default.res opengl.res
+#> java -jar dist/J2DAnalyzer.jar default.res opengl.res
Note that you can compare more than two sets of results, see
J2DAnalyzer's help page.
--- a/jdk/src/demo/share/java2d/J2DBench/build.xml Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/demo/share/java2d/J2DBench/build.xml Wed Jul 05 19:59:54 2017 +0200
@@ -49,7 +49,7 @@
<target name="compile" depends="init"
description="compile the source " >
<!-- Compile the java code from ${src} into ${build} -->
- <javac debug="flase" source="1.5" target="1.5" srcdir="${src}" destdir="${build}"/>
+ <javac debug="off" source="1.6" target="1.6" srcdir="${src}" destdir="${build}"/>
</target>
<target name="run" depends="dist"
--- a/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/CMMTests.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/CMMTests.java Wed Jul 05 19:59:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -39,23 +39,24 @@
package j2dbench.tests.cmm;
-import j2dbench.Group;
-import j2dbench.Option;
-import j2dbench.Result;
-import j2dbench.Test;
-import j2dbench.TestEnvironment;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile;
import java.io.IOException;
import java.io.InputStream;
+import j2dbench.Group;
+import j2dbench.Option;
+import j2dbench.Result;
+import j2dbench.Test;
+import j2dbench.TestEnvironment;
+
public class CMMTests extends Test {
protected static Group cmmRoot;
protected static Group cmmOptRoot;
protected static Option csList;
- protected static Option usePlatfromProfiles;
+ protected static Option usePlatformProfiles;
public static void init() {
cmmRoot = new Group("cmm", "Color Management Benchmarks");
@@ -64,9 +65,9 @@
cmmOptRoot = new Group(cmmRoot, "opts", "General Options");
/*
- usePlatfromProfiles =
- new Option.Enable(cmmOptRoot, "csPlatfrom",
- "Use Platfrom Profiles", false);
+ usePlatformProfiles =
+ new Option.Enable(cmmOptRoot, "csPlatform",
+ "Use Platform Profiles", false);
*/
int[] colorspaces = new int[] {
ColorSpace.CS_sRGB,
@@ -92,10 +93,10 @@
protected static ColorSpace getColorSpace(TestEnvironment env) {
ColorSpace cs;
- Boolean usePlatfrom = true; //(Boolean)env.getModifier(usePlatfromProfiles);
+ boolean usePlatform = true; //(Boolean)env.getModifier(usePlatformProfiles);
int cs_code = env.getIntValue(csList);
- if (usePlatfrom) {
+ if (usePlatform) {
cs = ColorSpace.getInstance(cs_code);
} else {
String resource = "profiles/";
@@ -136,17 +137,14 @@
addDependencies(cmmOptRoot, true);
}
- @Override
public Object initTest(TestEnvironment te, Result result) {
throw new UnsupportedOperationException("Not supported yet.");
}
- @Override
public void runTest(Object o, int i) {
throw new UnsupportedOperationException("Not supported yet.");
}
- @Override
public void cleanupTest(TestEnvironment te, Object o) {
throw new UnsupportedOperationException("Not supported yet.");
}
--- a/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/ColorConvertOpTests.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/ColorConvertOpTests.java Wed Jul 05 19:59:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -39,11 +39,6 @@
package j2dbench.tests.cmm;
-import j2dbench.Group;
-import j2dbench.Option;
-import j2dbench.Result;
-import j2dbench.TestEnvironment;
-import j2dbench.tests.iio.IIOTests;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
@@ -53,15 +48,22 @@
import java.awt.image.ColorConvertOp;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
+
import javax.imageio.ImageIO;
+import j2dbench.Group;
+import j2dbench.Option;
+import j2dbench.Result;
+import j2dbench.TestEnvironment;
+import j2dbench.tests.iio.IIOTests;
+
public class ColorConvertOpTests extends ColorConversionTests {
- private static enum ImageContent {
- BLANK("bank", "Blank (opaque black)"),
- RANDOM("random", "Random"),
- VECTOR("vector", "Vector Art"),
- PHOTO("photo", "Photograph");
+ private static class ImageContent {
+ static ImageContent BLANK = new ImageContent("bank", "Blank (opaque black)");
+ static ImageContent RANDOM = new ImageContent("random", "Random");
+ static ImageContent VECTOR = new ImageContent("vector", "Vector Art");
+ static ImageContent PHOTO= new ImageContent("photo", "Photograph");
public final String name;
public final String descr;
@@ -70,15 +72,19 @@
this.name = name;
this.descr = descr;
}
+
+ public static ImageContent[] values() {
+ return new ImageContent[]{BLANK, RANDOM, VECTOR, PHOTO};
+ }
}
- private static enum ImageType {
- INT_ARGB(BufferedImage.TYPE_INT_ARGB, "INT_ARGB", "TYPE_INT_ARGB"),
- INT_RGB(BufferedImage.TYPE_INT_RGB, "INT_RGB", "TYPE_INT_RGB"),
- INT_BGR(BufferedImage.TYPE_INT_BGR, "INT_BGR", "TYPE_INT_BGR"),
- BYTE_3BYTE_BGR(BufferedImage.TYPE_3BYTE_BGR, "3BYTE_BGR", "TYPE_3BYTE_BGR"),
- BYTE_4BYTE_ABGR(BufferedImage.TYPE_4BYTE_ABGR, "4BYTE_BGR", "TYPE_4BYTE_BGR"),
- COMPATIBLE_DST(0, "Compatible", "Compatible destination");
+ private static class ImageType {
+ static ImageType INT_ARGB = new ImageType(BufferedImage.TYPE_INT_ARGB, "INT_ARGB", "TYPE_INT_ARGB");
+ static ImageType INT_RGB = new ImageType(BufferedImage.TYPE_INT_RGB, "INT_RGB", "TYPE_INT_RGB");
+ static ImageType INT_BGR = new ImageType(BufferedImage.TYPE_INT_BGR, "INT_BGR", "TYPE_INT_BGR");
+ static ImageType BYTE_3BYTE_BGR = new ImageType(BufferedImage.TYPE_3BYTE_BGR, "3BYTE_BGR", "TYPE_3BYTE_BGR");
+ static ImageType BYTE_4BYTE_ABGR = new ImageType(BufferedImage.TYPE_4BYTE_ABGR, "4BYTE_BGR", "TYPE_4BYTE_BGR");
+ static ImageType COMPATIBLE_DST = new ImageType(0, "Compatible", "Compatible destination");
private ImageType(int type, String abbr, String descr) {
this.type = type;
@@ -89,11 +95,16 @@
public final int type;
public final String abbrev;
public final String descr;
+
+ public static ImageType[] values() {
+ return new ImageType[]{INT_ARGB, INT_RGB, INT_BGR,
+ BYTE_3BYTE_BGR, BYTE_4BYTE_ABGR, COMPATIBLE_DST};
+ }
}
- private static enum ListType {
- SRC("srcType", "Source Images"),
- DST("dstType", "Destination Images");
+ private static class ListType {
+ static ListType SRC = new ListType("srcType", "Source Images");
+ static ListType DST = new ListType("dstType", "Destination Images");
private ListType(String name, String description) {
this.name = name;
@@ -320,64 +331,55 @@
BufferedImage image;
image = new BufferedImage(width, height, type);
boolean hasAlpha = image.getColorModel().hasAlpha();
- switch (contentType) {
- case RANDOM:
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- int rgb = (int)(Math.random() * 0xffffff);
- if (hasAlpha) {
- rgb |= 0x7f000000;
- }
- image.setRGB(x, y, rgb);
- }
- }
- break;
- case VECTOR:
- {
- Graphics2D g = image.createGraphics();
+ if (contentType == ImageContent.RANDOM) {
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int rgb = (int) (Math.random() * 0xffffff);
if (hasAlpha) {
- // fill background with a translucent color
- g.setComposite(AlphaComposite.getInstance(
- AlphaComposite.SRC, 0.5f));
+ rgb |= 0x7f000000;
}
- g.setColor(Color.blue);
- g.fillRect(0, 0, width, height);
- g.setComposite(AlphaComposite.Src);
- g.setColor(Color.yellow);
- g.fillOval(2, 2, width-4, height-4);
- g.setColor(Color.red);
- g.fillOval(4, 4, width-8, height-8);
- g.setColor(Color.green);
- g.fillRect(8, 8, width-16, height-16);
- g.setColor(Color.white);
- g.drawLine(0, 0, width, height);
- g.drawLine(0, height, width, 0);
- g.dispose();
- break;
+ image.setRGB(x, y, rgb);
}
- case PHOTO:
- {
- Image photo = null;
- try {
- photo = ImageIO.read(
- IIOTests.class.getResourceAsStream("images/photo.jpg"));
- } catch (Exception e) {
- System.err.println("error loading photo");
- e.printStackTrace();
- }
- Graphics2D g = image.createGraphics();
- if (hasAlpha) {
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC,
- 0.5f));
- }
- g.drawImage(photo, 0, 0, width, height, null);
- g.dispose();
- break;
- }
- default:
- break;
+ }
}
-
+ if (contentType == ImageContent.VECTOR) {
+ Graphics2D g = image.createGraphics();
+ if (hasAlpha) {
+ // fill background with a translucent color
+ g.setComposite(AlphaComposite.getInstance(
+ AlphaComposite.SRC, 0.5f));
+ }
+ g.setColor(Color.blue);
+ g.fillRect(0, 0, width, height);
+ g.setComposite(AlphaComposite.Src);
+ g.setColor(Color.yellow);
+ g.fillOval(2, 2, width-4, height-4);
+ g.setColor(Color.red);
+ g.fillOval(4, 4, width-8, height-8);
+ g.setColor(Color.green);
+ g.fillRect(8, 8, width-16, height-16);
+ g.setColor(Color.white);
+ g.drawLine(0, 0, width, height);
+ g.drawLine(0, height, width, 0);
+ g.dispose();
+ }
+ if (contentType == ImageContent.PHOTO) {
+ Image photo = null;
+ try {
+ photo = ImageIO.read(
+ IIOTests.class.getResourceAsStream("images/photo.jpg"));
+ } catch (Exception e) {
+ System.err.println("error loading photo");
+ e.printStackTrace();
+ }
+ Graphics2D g = image.createGraphics();
+ if (hasAlpha) {
+ g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC,
+ 0.5f));
+ }
+ g.drawImage(photo, 0, 0, width, height, null);
+ g.dispose();
+ }
return image;
}
}
--- a/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/DataConversionTests.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/DataConversionTests.java Wed Jul 05 19:59:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -39,10 +39,11 @@
package j2dbench.tests.cmm;
+import java.awt.color.ColorSpace;
+
import j2dbench.Group;
import j2dbench.Result;
import j2dbench.TestEnvironment;
-import java.awt.color.ColorSpace;
public class DataConversionTests extends ColorConversionTests {
@@ -92,13 +93,11 @@
}
}
- @Override
public Object initTest(TestEnvironment env, Result result) {
ColorSpace cs = getColorSpace(env);
return new Context(env, result, cs);
}
- @Override
public void cleanupTest(TestEnvironment te, Object o) {
}
--- a/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/EmbeddedProfileTests.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/EmbeddedProfileTests.java Wed Jul 05 19:59:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -39,16 +39,18 @@
package j2dbench.tests.cmm;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.net.URL;
+
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.ImageInputStream;
+
import j2dbench.Group;
import j2dbench.Option;
import j2dbench.Result;
import j2dbench.TestEnvironment;
-import java.awt.image.BufferedImage;
-import java.io.IOException;
-import java.net.URL;
-import javax.imageio.ImageIO;
-import javax.imageio.ImageReader;
-import javax.imageio.stream.ImageInputStream;
/* This benchmark verifies how changes in cmm library affects image decoding */
public class EmbeddedProfileTests extends ColorConversionTests {
@@ -68,10 +70,10 @@
new ReadImageTest();
}
- private static enum IccImageResource {
- SMALL("images/img_icc_small.jpg", "512x512", "Small: 512x512"),
- MEDIUM("images/img_icc_medium.jpg", "2048x2048", "Medium: 2048x2048"),
- LARGE("images/img_icc_large.jpg", "4096x4096", "Large: 4096x4096");
+ private static class IccImageResource {
+ static IccImageResource SMALL = new IccImageResource("images/img_icc_small.jpg", "512x512", "Small: 512x512");
+ static IccImageResource MEDIUM = new IccImageResource("images/img_icc_medium.jpg", "2048x2048", "Medium: 2048x2048");
+ static IccImageResource LARGE = new IccImageResource("images/img_icc_large.jpg", "4096x4096", "Large: 4096x4096");
private IccImageResource(String file, String name, String description) {
this.url = CMMTests.class.getResource(file);
@@ -82,6 +84,10 @@
public final URL url;
public final String abbrev;
public final String description;
+
+ public static IccImageResource[] values() {
+ return new IccImageResource[]{SMALL, MEDIUM, LARGE};
+ }
}
private static Option createImageList() {
@@ -145,7 +151,7 @@
try {
iis = ImageIO.createImageInputStream(url.openStream());
- reader = ImageIO.getImageReaders(iis).next();
+ reader = (ImageReader) ImageIO.getImageReaders(iis).next();
} catch (IOException e) {
throw new RuntimeException("Unable to run the becnhmark", e);
}
--- a/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/ProfileTests.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/ProfileTests.java Wed Jul 05 19:59:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -38,12 +38,12 @@
*/
package j2dbench.tests.cmm;
+import java.awt.color.ICC_ColorSpace;
+import java.awt.color.ICC_Profile;
+
import j2dbench.Group;
import j2dbench.Result;
import j2dbench.TestEnvironment;
-import java.awt.color.ColorSpace;
-import java.awt.color.ICC_ColorSpace;
-import java.awt.color.ICC_Profile;
public class ProfileTests extends CMMTests {
@@ -73,13 +73,11 @@
}
}
- @Override
public Object initTest(TestEnvironment env, Result res) {
ICC_ColorSpace cs = (ICC_ColorSpace) getColorSpace(env);
return new Context(cs.getProfile(), env, res);
}
- @Override
public void cleanupTest(TestEnvironment env, Object o) {
}
@@ -91,7 +89,6 @@
"getData(icSigHead)");
}
- @Override
public void runTest(Object ctx, int numReps) {
final Context ictx = (Context) ctx;
final ICC_Profile profile = ictx.profile;
@@ -115,7 +112,6 @@
"getNumComponents");
}
- @Override
public void runTest(Object ctx, int numReps) {
final Context ictx = (Context) ctx;
final ICC_Profile profile = ictx.profile;
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java Wed Jul 05 19:59:54 2017 +0200
@@ -50,7 +50,6 @@
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CompletionStage;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;
/**
@@ -77,9 +76,9 @@
* <li>All <em>async</em> methods without an explicit Executor
* argument are performed using the {@link ForkJoinPool#commonPool()}
* (unless it does not support a parallelism level of at least two, in
- * which case, a new Thread is used). To simplify monitoring,
- * debugging, and tracking, all generated asynchronous tasks are
- * instances of the marker interface {@link
+ * which case, a new Thread is created to run each task). To simplify
+ * monitoring, debugging, and tracking, all generated asynchronous
+ * tasks are instances of the marker interface {@link
* AsynchronousCompletionTask}. </li>
*
* <li>All CompletionStage methods are implemented independently of
@@ -113,141 +112,1556 @@
/*
* Overview:
*
- * 1. Non-nullness of field result (set via CAS) indicates done.
- * An AltResult is used to box null as a result, as well as to
- * hold exceptions. Using a single field makes completion fast
- * and simple to detect and trigger, at the expense of a lot of
- * encoding and decoding that infiltrates many methods. One minor
- * simplification relies on the (static) NIL (to box null results)
- * being the only AltResult with a null exception field, so we
- * don't usually need explicit comparisons with NIL. The CF
- * exception propagation mechanics surrounding decoding rely on
- * unchecked casts of decoded results really being unchecked,
- * where user type errors are caught at point of use, as is
- * currently the case in Java. These are highlighted by using
- * SuppressWarnings-annotated temporaries.
+ * A CompletableFuture may have dependent completion actions,
+ * collected in a linked stack. It atomically completes by CASing
+ * a result field, and then pops off and runs those actions. This
+ * applies across normal vs exceptional outcomes, sync vs async
+ * actions, binary triggers, and various forms of completions.
+ *
+ * Non-nullness of field result (set via CAS) indicates done. An
+ * AltResult is used to box null as a result, as well as to hold
+ * exceptions. Using a single field makes completion simple to
+ * detect and trigger. Encoding and decoding is straightforward
+ * but adds to the sprawl of trapping and associating exceptions
+ * with targets. Minor simplifications rely on (static) NIL (to
+ * box null results) being the only AltResult with a null
+ * exception field, so we don't usually need explicit comparisons.
+ * Even though some of the generics casts are unchecked (see
+ * SuppressWarnings annotations), they are placed to be
+ * appropriate even if checked.
*
- * 2. Waiters are held in a Treiber stack similar to the one used
- * in FutureTask, Phaser, and SynchronousQueue. See their
- * internal documentation for algorithmic details.
+ * Dependent actions are represented by Completion objects linked
+ * as Treiber stacks headed by field "stack". There are Completion
+ * classes for each kind of action, grouped into single-input
+ * (UniCompletion), two-input (BiCompletion), projected
+ * (BiCompletions using either (not both) of two inputs), shared
+ * (CoCompletion, used by the second of two sources), zero-input
+ * source actions, and Signallers that unblock waiters. Class
+ * Completion extends ForkJoinTask to enable async execution
+ * (adding no space overhead because we exploit its "tag" methods
+ * to maintain claims). It is also declared as Runnable to allow
+ * usage with arbitrary executors.
+ *
+ * Support for each kind of CompletionStage relies on a separate
+ * class, along with two CompletableFuture methods:
+ *
+ * * A Completion class with name X corresponding to function,
+ * prefaced with "Uni", "Bi", or "Or". Each class contains
+ * fields for source(s), actions, and dependent. They are
+ * boringly similar, differing from others only with respect to
+ * underlying functional forms. We do this so that users don't
+ * encounter layers of adaptors in common usages. We also
+ * include "Relay" classes/methods that don't correspond to user
+ * methods; they copy results from one stage to another.
+ *
+ * * Boolean CompletableFuture method x(...) (for example
+ * uniApply) takes all of the arguments needed to check that an
+ * action is triggerable, and then either runs the action or
+ * arranges its async execution by executing its Completion
+ * argument, if present. The method returns true if known to be
+ * complete.
*
- * 3. Completions are also kept in a list/stack, and pulled off
- * and run when completion is triggered. (We could even use the
- * same stack as for waiters, but would give up the potential
- * parallelism obtained because woken waiters help release/run
- * others -- see method postComplete). Because post-processing
- * may race with direct calls, class Completion opportunistically
- * extends AtomicInteger so callers can claim the action via
- * compareAndSet(0, 1). The Completion.run methods are all
- * written a boringly similar uniform way (that sometimes includes
- * unnecessary-looking checks, kept to maintain uniformity).
- * There are enough dimensions upon which they differ that
- * attempts to factor commonalities while maintaining efficiency
- * require more lines of code than they would save.
+ * * Completion method tryFire(int mode) invokes the associated x
+ * method with its held arguments, and on success cleans up.
+ * The mode argument allows tryFire to be called twice (SYNC,
+ * then ASYNC); the first to screen and trap exceptions while
+ * arranging to execute, and the second when called from a
+ * task. (A few classes are not used async so take slightly
+ * different forms.) The claim() callback suppresses function
+ * invocation if already claimed by another thread.
+ *
+ * * CompletableFuture method xStage(...) is called from a public
+ * stage method of CompletableFuture x. It screens user
+ * arguments and invokes and/or creates the stage object. If
+ * not async and x is already complete, the action is run
+ * immediately. Otherwise a Completion c is created, pushed to
+ * x's stack (unless done), and started or triggered via
+ * c.tryFire. This also covers races possible if x completes
+ * while pushing. Classes with two inputs (for example BiApply)
+ * deal with races across both while pushing actions. The
+ * second completion is a CoCompletion pointing to the first,
+ * shared so that at most one performs the action. The
+ * multiple-arity methods allOf and anyOf do this pairwise to
+ * form trees of completions.
+ *
+ * Note that the generic type parameters of methods vary according
+ * to whether "this" is a source, dependent, or completion.
*
- * 4. The exported then/and/or methods do support a bit of
- * factoring (see doThenApply etc). They must cope with the
- * intrinsic races surrounding addition of a dependent action
- * versus performing the action directly because the task is
- * already complete. For example, a CF may not be complete upon
- * entry, so a dependent completion is added, but by the time it
- * is added, the target CF is complete, so must be directly
- * executed. This is all done while avoiding unnecessary object
- * construction in safe-bypass cases.
+ * Method postComplete is called upon completion unless the target
+ * is guaranteed not to be observable (i.e., not yet returned or
+ * linked). Multiple threads can call postComplete, which
+ * atomically pops each dependent action, and tries to trigger it
+ * via method tryFire, in NESTED mode. Triggering can propagate
+ * recursively, so NESTED mode returns its completed dependent (if
+ * one exists) for further processing by its caller (see method
+ * postFire).
+ *
+ * Blocking methods get() and join() rely on Signaller Completions
+ * that wake up waiting threads. The mechanics are similar to
+ * Treiber stack wait-nodes used in FutureTask, Phaser, and
+ * SynchronousQueue. See their internal documentation for
+ * algorithmic details.
+ *
+ * Without precautions, CompletableFutures would be prone to
+ * garbage accumulation as chains of Completions build up, each
+ * pointing back to its sources. So we null out fields as soon as
+ * possible (see especially method Completion.detach). The
+ * screening checks needed anyway harmlessly ignore null arguments
+ * that may have been obtained during races with threads nulling
+ * out fields. We also try to unlink fired Completions from
+ * stacks that might never be popped (see method postFire).
+ * Completion fields need not be declared as final or volatile
+ * because they are only visible to other threads upon safe
+ * publication.
*/
- // preliminaries
+ volatile Object result; // Either the result or boxed AltResult
+ volatile Completion stack; // Top of Treiber stack of dependent actions
+
+ final boolean internalComplete(Object r) { // CAS from null to r
+ return UNSAFE.compareAndSwapObject(this, RESULT, null, r);
+ }
+
+ final boolean casStack(Completion cmp, Completion val) {
+ return UNSAFE.compareAndSwapObject(this, STACK, cmp, val);
+ }
+
+ /** Returns true if successfully pushed c onto stack. */
+ final boolean tryPushStack(Completion c) {
+ Completion h = stack;
+ lazySetNext(c, h);
+ return UNSAFE.compareAndSwapObject(this, STACK, h, c);
+ }
+
+ /** Unconditionally pushes c onto stack, retrying if necessary. */
+ final void pushStack(Completion c) {
+ do {} while (!tryPushStack(c));
+ }
+
+ /* ------------- Encoding and decoding outcomes -------------- */
+
+ static final class AltResult { // See above
+ final Throwable ex; // null only for NIL
+ AltResult(Throwable x) { this.ex = x; }
+ }
- static final class AltResult {
- final Throwable ex; // null only for NIL
- AltResult(Throwable ex) { this.ex = ex; }
+ /** The encoding of the null value. */
+ static final AltResult NIL = new AltResult(null);
+
+ /** Completes with the null value, unless already completed. */
+ final boolean completeNull() {
+ return UNSAFE.compareAndSwapObject(this, RESULT, null,
+ NIL);
+ }
+
+ /** Returns the encoding of the given non-exceptional value. */
+ final Object encodeValue(T t) {
+ return (t == null) ? NIL : t;
+ }
+
+ /** Completes with a non-exceptional result, unless already completed. */
+ final boolean completeValue(T t) {
+ return UNSAFE.compareAndSwapObject(this, RESULT, null,
+ (t == null) ? NIL : t);
+ }
+
+ /**
+ * Returns the encoding of the given (non-null) exception as a
+ * wrapped CompletionException unless it is one already.
+ */
+ static AltResult encodeThrowable(Throwable x) {
+ return new AltResult((x instanceof CompletionException) ? x :
+ new CompletionException(x));
+ }
+
+ /** Completes with an exceptional result, unless already completed. */
+ final boolean completeThrowable(Throwable x) {
+ return UNSAFE.compareAndSwapObject(this, RESULT, null,
+ encodeThrowable(x));
}
- static final AltResult NIL = new AltResult(null);
+ /**
+ * Returns the encoding of the given (non-null) exception as a
+ * wrapped CompletionException unless it is one already. May
+ * return the given Object r (which must have been the result of a
+ * source future) if it is equivalent, i.e. if this is a simple
+ * relay of an existing CompletionException.
+ */
+ static Object encodeThrowable(Throwable x, Object r) {
+ if (!(x instanceof CompletionException))
+ x = new CompletionException(x);
+ else if (r instanceof AltResult && x == ((AltResult)r).ex)
+ return r;
+ return new AltResult(x);
+ }
- // Fields
+ /**
+ * Completes with the given (non-null) exceptional result as a
+ * wrapped CompletionException unless it is one already, unless
+ * already completed. May complete with the given Object r
+ * (which must have been the result of a source future) if it is
+ * equivalent, i.e. if this is a simple propagation of an
+ * existing CompletionException.
+ */
+ final boolean completeThrowable(Throwable x, Object r) {
+ return UNSAFE.compareAndSwapObject(this, RESULT, null,
+ encodeThrowable(x, r));
+ }
+
+ /**
+ * Returns the encoding of the given arguments: if the exception
+ * is non-null, encodes as AltResult. Otherwise uses the given
+ * value, boxed as NIL if null.
+ */
+ Object encodeOutcome(T t, Throwable x) {
+ return (x == null) ? (t == null) ? NIL : t : encodeThrowable(x);
+ }
- volatile Object result; // Either the result or boxed AltResult
- volatile WaitNode waiters; // Treiber stack of threads blocked on get()
- volatile CompletionNode completions; // list (Treiber stack) of completions
+ /**
+ * Returns the encoding of a copied outcome; if exceptional,
+ * rewraps as a CompletionException, else returns argument.
+ */
+ static Object encodeRelay(Object r) {
+ Throwable x;
+ return (((r instanceof AltResult) &&
+ (x = ((AltResult)r).ex) != null &&
+ !(x instanceof CompletionException)) ?
+ new AltResult(new CompletionException(x)) : r);
+ }
+
+ /**
+ * Completes with r or a copy of r, unless already completed.
+ * If exceptional, r is first coerced to a CompletionException.
+ */
+ final boolean completeRelay(Object r) {
+ return UNSAFE.compareAndSwapObject(this, RESULT, null,
+ encodeRelay(r));
+ }
- // Basic utilities for triggering and processing completions
+ /**
+ * Reports result using Future.get conventions.
+ */
+ private static <T> T reportGet(Object r)
+ throws InterruptedException, ExecutionException {
+ if (r == null) // by convention below, null means interrupted
+ throw new InterruptedException();
+ if (r instanceof AltResult) {
+ Throwable x, cause;
+ if ((x = ((AltResult)r).ex) == null)
+ return null;
+ if (x instanceof CancellationException)
+ throw (CancellationException)x;
+ if ((x instanceof CompletionException) &&
+ (cause = x.getCause()) != null)
+ x = cause;
+ throw new ExecutionException(x);
+ }
+ @SuppressWarnings("unchecked") T t = (T) r;
+ return t;
+ }
/**
- * Removes and signals all waiting threads and runs all completions.
+ * Decodes outcome to return result or throw unchecked exception.
+ */
+ private static <T> T reportJoin(Object r) {
+ if (r instanceof AltResult) {
+ Throwable x;
+ if ((x = ((AltResult)r).ex) == null)
+ return null;
+ if (x instanceof CancellationException)
+ throw (CancellationException)x;
+ if (x instanceof CompletionException)
+ throw (CompletionException)x;
+ throw new CompletionException(x);
+ }
+ @SuppressWarnings("unchecked") T t = (T) r;
+ return t;
+ }
+
+ /* ------------- Async task preliminaries -------------- */
+
+ /**
+ * A marker interface identifying asynchronous tasks produced by
+ * {@code async} methods. This may be useful for monitoring,
+ * debugging, and tracking asynchronous activities.
+ *
+ * @since 1.8
+ */
+ public static interface AsynchronousCompletionTask {
+ }
+
+ private static final boolean useCommonPool =
+ (ForkJoinPool.getCommonPoolParallelism() > 1);
+
+ /**
+ * Default executor -- ForkJoinPool.commonPool() unless it cannot
+ * support parallelism.
+ */
+ private static final Executor asyncPool = useCommonPool ?
+ ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
+
+ /** Fallback if ForkJoinPool.commonPool() cannot support parallelism */
+ static final class ThreadPerTaskExecutor implements Executor {
+ public void execute(Runnable r) { new Thread(r).start(); }
+ }
+
+ /**
+ * Null-checks user executor argument, and translates uses of
+ * commonPool to asyncPool in case parallelism disabled.
+ */
+ static Executor screenExecutor(Executor e) {
+ if (!useCommonPool && e == ForkJoinPool.commonPool())
+ return asyncPool;
+ if (e == null) throw new NullPointerException();
+ return e;
+ }
+
+ // Modes for Completion.tryFire. Signedness matters.
+ static final int SYNC = 0;
+ static final int ASYNC = 1;
+ static final int NESTED = -1;
+
+ /* ------------- Base Completion classes and operations -------------- */
+
+ @SuppressWarnings("serial")
+ abstract static class Completion extends ForkJoinTask<Void>
+ implements Runnable, AsynchronousCompletionTask {
+ volatile Completion next; // Treiber stack link
+
+ /**
+ * Performs completion action if triggered, returning a
+ * dependent that may need propagation, if one exists.
+ *
+ * @param mode SYNC, ASYNC, or NESTED
+ */
+ abstract CompletableFuture<?> tryFire(int mode);
+
+ /** Returns true if possibly still triggerable. Used by cleanStack. */
+ abstract boolean isLive();
+
+ public final void run() { tryFire(ASYNC); }
+ public final boolean exec() { tryFire(ASYNC); return true; }
+ public final Void getRawResult() { return null; }
+ public final void setRawResult(Void v) {}
+ }
+
+ static void lazySetNext(Completion c, Completion next) {
+ UNSAFE.putOrderedObject(c, NEXT, next);
+ }
+
+ /**
+ * Pops and tries to trigger all reachable dependents. Call only
+ * when known to be done.
*/
final void postComplete() {
- WaitNode q; Thread t;
- while ((q = waiters) != null) {
- if (UNSAFE.compareAndSwapObject(this, WAITERS, q, q.next) &&
- (t = q.thread) != null) {
- q.thread = null;
- LockSupport.unpark(t);
+ /*
+ * On each step, variable f holds current dependents to pop
+ * and run. It is extended along only one path at a time,
+ * pushing others to avoid unbounded recursion.
+ */
+ CompletableFuture<?> f = this; Completion h;
+ while ((h = f.stack) != null ||
+ (f != this && (h = (f = this).stack) != null)) {
+ CompletableFuture<?> d; Completion t;
+ if (f.casStack(h, t = h.next)) {
+ if (t != null) {
+ if (f != this) {
+ pushStack(h);
+ continue;
+ }
+ h.next = null; // detach
+ }
+ f = (d = h.tryFire(NESTED)) == null ? this : d;
}
}
+ }
- CompletionNode h; Completion c;
- while ((h = completions) != null) {
- if (UNSAFE.compareAndSwapObject(this, COMPLETIONS, h, h.next) &&
- (c = h.completion) != null)
- c.run();
+ /** Traverses stack and unlinks dead Completions. */
+ final void cleanStack() {
+ for (Completion p = null, q = stack; q != null;) {
+ Completion s = q.next;
+ if (q.isLive()) {
+ p = q;
+ q = s;
+ }
+ else if (p == null) {
+ casStack(q, s);
+ q = stack;
+ }
+ else {
+ p.next = s;
+ if (p.isLive())
+ q = s;
+ else {
+ p = null; // restart
+ q = stack;
+ }
+ }
+ }
+ }
+
+ /* ------------- One-input Completions -------------- */
+
+ /** A Completion with a source, dependent, and executor. */
+ @SuppressWarnings("serial")
+ abstract static class UniCompletion<T,V> extends Completion {
+ Executor executor; // executor to use (null if none)
+ CompletableFuture<V> dep; // the dependent to complete
+ CompletableFuture<T> src; // source for action
+
+ UniCompletion(Executor executor, CompletableFuture<V> dep,
+ CompletableFuture<T> src) {
+ this.executor = executor; this.dep = dep; this.src = src;
+ }
+
+ /**
+ * Returns true if action can be run. Call only when known to
+ * be triggerable. Uses FJ tag bit to ensure that only one
+ * thread claims ownership. If async, starts as task -- a
+ * later call to tryFire will run action.
+ */
+ final boolean claim() {
+ Executor e = executor;
+ if (compareAndSetForkJoinTaskTag((short)0, (short)1)) {
+ if (e == null)
+ return true;
+ executor = null; // disable
+ e.execute(this);
+ }
+ return false;
+ }
+
+ final boolean isLive() { return dep != null; }
+ }
+
+ /** Pushes the given completion (if it exists) unless done. */
+ final void push(UniCompletion<?,?> c) {
+ if (c != null) {
+ while (result == null && !tryPushStack(c))
+ lazySetNext(c, null); // clear on failure
}
}
/**
- * Triggers completion with the encoding of the given arguments:
- * if the exception is non-null, encodes it as a wrapped
- * CompletionException unless it is one already. Otherwise uses
- * the given result, boxed as NIL if null.
+ * Post-processing by dependent after successful UniCompletion
+ * tryFire. Tries to clean stack of source a, and then either runs
+ * postComplete or returns this to caller, depending on mode.
*/
- final void internalComplete(T v, Throwable ex) {
- if (result == null)
- UNSAFE.compareAndSwapObject
- (this, RESULT, null,
- (ex == null) ? (v == null) ? NIL : v :
- new AltResult((ex instanceof CompletionException) ? ex :
- new CompletionException(ex)));
- postComplete(); // help out even if not triggered
+ final CompletableFuture<T> postFire(CompletableFuture<?> a, int mode) {
+ if (a != null && a.stack != null) {
+ if (mode < 0 || a.result == null)
+ a.cleanStack();
+ else
+ a.postComplete();
+ }
+ if (result != null && stack != null) {
+ if (mode < 0)
+ return this;
+ else
+ postComplete();
+ }
+ return null;
+ }
+
+ @SuppressWarnings("serial")
+ static final class UniApply<T,V> extends UniCompletion<T,V> {
+ Function<? super T,? extends V> fn;
+ UniApply(Executor executor, CompletableFuture<V> dep,
+ CompletableFuture<T> src,
+ Function<? super T,? extends V> fn) {
+ super(executor, dep, src); this.fn = fn;
+ }
+ final CompletableFuture<V> tryFire(int mode) {
+ CompletableFuture<V> d; CompletableFuture<T> a;
+ if ((d = dep) == null ||
+ !d.uniApply(a = src, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; fn = null;
+ return d.postFire(a, mode);
+ }
+ }
+
+ final <S> boolean uniApply(CompletableFuture<S> a,
+ Function<? super S,? extends T> f,
+ UniApply<S,T> c) {
+ Object r; Throwable x;
+ if (a == null || (r = a.result) == null || f == null)
+ return false;
+ tryComplete: if (result == null) {
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ try {
+ if (c != null && !c.claim())
+ return false;
+ @SuppressWarnings("unchecked") S s = (S) r;
+ completeValue(f.apply(s));
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private <V> CompletableFuture<V> uniApplyStage(
+ Executor e, Function<? super T,? extends V> f) {
+ if (f == null) throw new NullPointerException();
+ CompletableFuture<V> d = new CompletableFuture<V>();
+ if (e != null || !d.uniApply(this, f, null)) {
+ UniApply<T,V> c = new UniApply<T,V>(e, d, this, f);
+ push(c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class UniAccept<T> extends UniCompletion<T,Void> {
+ Consumer<? super T> fn;
+ UniAccept(Executor executor, CompletableFuture<Void> dep,
+ CompletableFuture<T> src, Consumer<? super T> fn) {
+ super(executor, dep, src); this.fn = fn;
+ }
+ final CompletableFuture<Void> tryFire(int mode) {
+ CompletableFuture<Void> d; CompletableFuture<T> a;
+ if ((d = dep) == null ||
+ !d.uniAccept(a = src, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; fn = null;
+ return d.postFire(a, mode);
+ }
+ }
+
+ final <S> boolean uniAccept(CompletableFuture<S> a,
+ Consumer<? super S> f, UniAccept<S> c) {
+ Object r; Throwable x;
+ if (a == null || (r = a.result) == null || f == null)
+ return false;
+ tryComplete: if (result == null) {
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ try {
+ if (c != null && !c.claim())
+ return false;
+ @SuppressWarnings("unchecked") S s = (S) r;
+ f.accept(s);
+ completeNull();
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private CompletableFuture<Void> uniAcceptStage(Executor e,
+ Consumer<? super T> f) {
+ if (f == null) throw new NullPointerException();
+ CompletableFuture<Void> d = new CompletableFuture<Void>();
+ if (e != null || !d.uniAccept(this, f, null)) {
+ UniAccept<T> c = new UniAccept<T>(e, d, this, f);
+ push(c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class UniRun<T> extends UniCompletion<T,Void> {
+ Runnable fn;
+ UniRun(Executor executor, CompletableFuture<Void> dep,
+ CompletableFuture<T> src, Runnable fn) {
+ super(executor, dep, src); this.fn = fn;
+ }
+ final CompletableFuture<Void> tryFire(int mode) {
+ CompletableFuture<Void> d; CompletableFuture<T> a;
+ if ((d = dep) == null ||
+ !d.uniRun(a = src, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; fn = null;
+ return d.postFire(a, mode);
+ }
+ }
+
+ final boolean uniRun(CompletableFuture<?> a, Runnable f, UniRun<?> c) {
+ Object r; Throwable x;
+ if (a == null || (r = a.result) == null || f == null)
+ return false;
+ if (result == null) {
+ if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+ completeThrowable(x, r);
+ else
+ try {
+ if (c != null && !c.claim())
+ return false;
+ f.run();
+ completeNull();
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private CompletableFuture<Void> uniRunStage(Executor e, Runnable f) {
+ if (f == null) throw new NullPointerException();
+ CompletableFuture<Void> d = new CompletableFuture<Void>();
+ if (e != null || !d.uniRun(this, f, null)) {
+ UniRun<T> c = new UniRun<T>(e, d, this, f);
+ push(c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class UniWhenComplete<T> extends UniCompletion<T,T> {
+ BiConsumer<? super T, ? super Throwable> fn;
+ UniWhenComplete(Executor executor, CompletableFuture<T> dep,
+ CompletableFuture<T> src,
+ BiConsumer<? super T, ? super Throwable> fn) {
+ super(executor, dep, src); this.fn = fn;
+ }
+ final CompletableFuture<T> tryFire(int mode) {
+ CompletableFuture<T> d; CompletableFuture<T> a;
+ if ((d = dep) == null ||
+ !d.uniWhenComplete(a = src, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; fn = null;
+ return d.postFire(a, mode);
+ }
+ }
+
+ final boolean uniWhenComplete(CompletableFuture<T> a,
+ BiConsumer<? super T,? super Throwable> f,
+ UniWhenComplete<T> c) {
+ Object r; T t; Throwable x = null;
+ if (a == null || (r = a.result) == null || f == null)
+ return false;
+ if (result == null) {
+ try {
+ if (c != null && !c.claim())
+ return false;
+ if (r instanceof AltResult) {
+ x = ((AltResult)r).ex;
+ t = null;
+ } else {
+ @SuppressWarnings("unchecked") T tr = (T) r;
+ t = tr;
+ }
+ f.accept(t, x);
+ if (x == null) {
+ internalComplete(r);
+ return true;
+ }
+ } catch (Throwable ex) {
+ if (x == null)
+ x = ex;
+ }
+ completeThrowable(x, r);
+ }
+ return true;
+ }
+
+ private CompletableFuture<T> uniWhenCompleteStage(
+ Executor e, BiConsumer<? super T, ? super Throwable> f) {
+ if (f == null) throw new NullPointerException();
+ CompletableFuture<T> d = new CompletableFuture<T>();
+ if (e != null || !d.uniWhenComplete(this, f, null)) {
+ UniWhenComplete<T> c = new UniWhenComplete<T>(e, d, this, f);
+ push(c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class UniHandle<T,V> extends UniCompletion<T,V> {
+ BiFunction<? super T, Throwable, ? extends V> fn;
+ UniHandle(Executor executor, CompletableFuture<V> dep,
+ CompletableFuture<T> src,
+ BiFunction<? super T, Throwable, ? extends V> fn) {
+ super(executor, dep, src); this.fn = fn;
+ }
+ final CompletableFuture<V> tryFire(int mode) {
+ CompletableFuture<V> d; CompletableFuture<T> a;
+ if ((d = dep) == null ||
+ !d.uniHandle(a = src, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; fn = null;
+ return d.postFire(a, mode);
+ }
}
- /**
- * If triggered, helps release and/or process completions.
- */
- final void helpPostComplete() {
- if (result != null)
- postComplete();
+ final <S> boolean uniHandle(CompletableFuture<S> a,
+ BiFunction<? super S, Throwable, ? extends T> f,
+ UniHandle<S,T> c) {
+ Object r; S s; Throwable x;
+ if (a == null || (r = a.result) == null || f == null)
+ return false;
+ if (result == null) {
+ try {
+ if (c != null && !c.claim())
+ return false;
+ if (r instanceof AltResult) {
+ x = ((AltResult)r).ex;
+ s = null;
+ } else {
+ x = null;
+ @SuppressWarnings("unchecked") S ss = (S) r;
+ s = ss;
+ }
+ completeValue(f.apply(s, x));
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private <V> CompletableFuture<V> uniHandleStage(
+ Executor e, BiFunction<? super T, Throwable, ? extends V> f) {
+ if (f == null) throw new NullPointerException();
+ CompletableFuture<V> d = new CompletableFuture<V>();
+ if (e != null || !d.uniHandle(this, f, null)) {
+ UniHandle<T,V> c = new UniHandle<T,V>(e, d, this, f);
+ push(c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class UniExceptionally<T> extends UniCompletion<T,T> {
+ Function<? super Throwable, ? extends T> fn;
+ UniExceptionally(CompletableFuture<T> dep, CompletableFuture<T> src,
+ Function<? super Throwable, ? extends T> fn) {
+ super(null, dep, src); this.fn = fn;
+ }
+ final CompletableFuture<T> tryFire(int mode) { // never ASYNC
+ // assert mode != ASYNC;
+ CompletableFuture<T> d; CompletableFuture<T> a;
+ if ((d = dep) == null || !d.uniExceptionally(a = src, fn, this))
+ return null;
+ dep = null; src = null; fn = null;
+ return d.postFire(a, mode);
+ }
+ }
+
+ final boolean uniExceptionally(CompletableFuture<T> a,
+ Function<? super Throwable, ? extends T> f,
+ UniExceptionally<T> c) {
+ Object r; Throwable x;
+ if (a == null || (r = a.result) == null || f == null)
+ return false;
+ if (result == null) {
+ try {
+ if (r instanceof AltResult && (x = ((AltResult)r).ex) != null) {
+ if (c != null && !c.claim())
+ return false;
+ completeValue(f.apply(x));
+ } else
+ internalComplete(r);
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private CompletableFuture<T> uniExceptionallyStage(
+ Function<Throwable, ? extends T> f) {
+ if (f == null) throw new NullPointerException();
+ CompletableFuture<T> d = new CompletableFuture<T>();
+ if (!d.uniExceptionally(this, f, null)) {
+ UniExceptionally<T> c = new UniExceptionally<T>(d, this, f);
+ push(c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class UniRelay<T> extends UniCompletion<T,T> { // for Compose
+ UniRelay(CompletableFuture<T> dep, CompletableFuture<T> src) {
+ super(null, dep, src);
+ }
+ final CompletableFuture<T> tryFire(int mode) {
+ CompletableFuture<T> d; CompletableFuture<T> a;
+ if ((d = dep) == null || !d.uniRelay(a = src))
+ return null;
+ src = null; dep = null;
+ return d.postFire(a, mode);
+ }
+ }
+
+ final boolean uniRelay(CompletableFuture<T> a) {
+ Object r;
+ if (a == null || (r = a.result) == null)
+ return false;
+ if (result == null) // no need to claim
+ completeRelay(r);
+ return true;
+ }
+
+ @SuppressWarnings("serial")
+ static final class UniCompose<T,V> extends UniCompletion<T,V> {
+ Function<? super T, ? extends CompletionStage<V>> fn;
+ UniCompose(Executor executor, CompletableFuture<V> dep,
+ CompletableFuture<T> src,
+ Function<? super T, ? extends CompletionStage<V>> fn) {
+ super(executor, dep, src); this.fn = fn;
+ }
+ final CompletableFuture<V> tryFire(int mode) {
+ CompletableFuture<V> d; CompletableFuture<T> a;
+ if ((d = dep) == null ||
+ !d.uniCompose(a = src, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; fn = null;
+ return d.postFire(a, mode);
+ }
+ }
+
+ final <S> boolean uniCompose(
+ CompletableFuture<S> a,
+ Function<? super S, ? extends CompletionStage<T>> f,
+ UniCompose<S,T> c) {
+ Object r; Throwable x;
+ if (a == null || (r = a.result) == null || f == null)
+ return false;
+ tryComplete: if (result == null) {
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ try {
+ if (c != null && !c.claim())
+ return false;
+ @SuppressWarnings("unchecked") S s = (S) r;
+ CompletableFuture<T> g = f.apply(s).toCompletableFuture();
+ if (g.result == null || !uniRelay(g)) {
+ UniRelay<T> copy = new UniRelay<T>(this, g);
+ g.push(copy);
+ copy.tryFire(SYNC);
+ if (result == null)
+ return false;
+ }
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private <V> CompletableFuture<V> uniComposeStage(
+ Executor e, Function<? super T, ? extends CompletionStage<V>> f) {
+ if (f == null) throw new NullPointerException();
+ Object r; Throwable x;
+ if (e == null && (r = result) != null) {
+ // try to return function result directly
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ return new CompletableFuture<V>(encodeThrowable(x, r));
+ }
+ r = null;
+ }
+ try {
+ @SuppressWarnings("unchecked") T t = (T) r;
+ return f.apply(t).toCompletableFuture();
+ } catch (Throwable ex) {
+ return new CompletableFuture<V>(encodeThrowable(ex));
+ }
+ }
+ CompletableFuture<V> d = new CompletableFuture<V>();
+ UniCompose<T,V> c = new UniCompose<T,V>(e, d, this, f);
+ push(c);
+ c.tryFire(SYNC);
+ return d;
+ }
+
+ /* ------------- Two-input Completions -------------- */
+
+ /** A Completion for an action with two sources */
+ @SuppressWarnings("serial")
+ abstract static class BiCompletion<T,U,V> extends UniCompletion<T,V> {
+ CompletableFuture<U> snd; // second source for action
+ BiCompletion(Executor executor, CompletableFuture<V> dep,
+ CompletableFuture<T> src, CompletableFuture<U> snd) {
+ super(executor, dep, src); this.snd = snd;
+ }
+ }
+
+ /** A Completion delegating to a BiCompletion */
+ @SuppressWarnings("serial")
+ static final class CoCompletion extends Completion {
+ BiCompletion<?,?,?> base;
+ CoCompletion(BiCompletion<?,?,?> base) { this.base = base; }
+ final CompletableFuture<?> tryFire(int mode) {
+ BiCompletion<?,?,?> c; CompletableFuture<?> d;
+ if ((c = base) == null || (d = c.tryFire(mode)) == null)
+ return null;
+ base = null; // detach
+ return d;
+ }
+ final boolean isLive() {
+ BiCompletion<?,?,?> c;
+ return (c = base) != null && c.dep != null;
+ }
+ }
+
+ /** Pushes completion to this and b unless both done. */
+ final void bipush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
+ if (c != null) {
+ Object r;
+ while ((r = result) == null && !tryPushStack(c))
+ lazySetNext(c, null); // clear on failure
+ if (b != null && b != this && b.result == null) {
+ Completion q = (r != null) ? c : new CoCompletion(c);
+ while (b.result == null && !b.tryPushStack(q))
+ lazySetNext(q, null); // clear on failure
+ }
+ }
+ }
+
+ /** Post-processing after successful BiCompletion tryFire. */
+ final CompletableFuture<T> postFire(CompletableFuture<?> a,
+ CompletableFuture<?> b, int mode) {
+ if (b != null && b.stack != null) { // clean second source
+ if (mode < 0 || b.result == null)
+ b.cleanStack();
+ else
+ b.postComplete();
+ }
+ return postFire(a, mode);
+ }
+
+ @SuppressWarnings("serial")
+ static final class BiApply<T,U,V> extends BiCompletion<T,U,V> {
+ BiFunction<? super T,? super U,? extends V> fn;
+ BiApply(Executor executor, CompletableFuture<V> dep,
+ CompletableFuture<T> src, CompletableFuture<U> snd,
+ BiFunction<? super T,? super U,? extends V> fn) {
+ super(executor, dep, src, snd); this.fn = fn;
+ }
+ final CompletableFuture<V> tryFire(int mode) {
+ CompletableFuture<V> d;
+ CompletableFuture<T> a;
+ CompletableFuture<U> b;
+ if ((d = dep) == null ||
+ !d.biApply(a = src, b = snd, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; snd = null; fn = null;
+ return d.postFire(a, b, mode);
+ }
}
- /* ------------- waiting for completions -------------- */
+ final <R,S> boolean biApply(CompletableFuture<R> a,
+ CompletableFuture<S> b,
+ BiFunction<? super R,? super S,? extends T> f,
+ BiApply<R,S,T> c) {
+ Object r, s; Throwable x;
+ if (a == null || (r = a.result) == null ||
+ b == null || (s = b.result) == null || f == null)
+ return false;
+ tryComplete: if (result == null) {
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ if (s instanceof AltResult) {
+ if ((x = ((AltResult)s).ex) != null) {
+ completeThrowable(x, s);
+ break tryComplete;
+ }
+ s = null;
+ }
+ try {
+ if (c != null && !c.claim())
+ return false;
+ @SuppressWarnings("unchecked") R rr = (R) r;
+ @SuppressWarnings("unchecked") S ss = (S) s;
+ completeValue(f.apply(rr, ss));
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private <U,V> CompletableFuture<V> biApplyStage(
+ Executor e, CompletionStage<U> o,
+ BiFunction<? super T,? super U,? extends V> f) {
+ CompletableFuture<U> b;
+ if (f == null || (b = o.toCompletableFuture()) == null)
+ throw new NullPointerException();
+ CompletableFuture<V> d = new CompletableFuture<V>();
+ if (e != null || !d.biApply(this, b, f, null)) {
+ BiApply<T,U,V> c = new BiApply<T,U,V>(e, d, this, b, f);
+ bipush(b, c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class BiAccept<T,U> extends BiCompletion<T,U,Void> {
+ BiConsumer<? super T,? super U> fn;
+ BiAccept(Executor executor, CompletableFuture<Void> dep,
+ CompletableFuture<T> src, CompletableFuture<U> snd,
+ BiConsumer<? super T,? super U> fn) {
+ super(executor, dep, src, snd); this.fn = fn;
+ }
+ final CompletableFuture<Void> tryFire(int mode) {
+ CompletableFuture<Void> d;
+ CompletableFuture<T> a;
+ CompletableFuture<U> b;
+ if ((d = dep) == null ||
+ !d.biAccept(a = src, b = snd, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; snd = null; fn = null;
+ return d.postFire(a, b, mode);
+ }
+ }
+
+ final <R,S> boolean biAccept(CompletableFuture<R> a,
+ CompletableFuture<S> b,
+ BiConsumer<? super R,? super S> f,
+ BiAccept<R,S> c) {
+ Object r, s; Throwable x;
+ if (a == null || (r = a.result) == null ||
+ b == null || (s = b.result) == null || f == null)
+ return false;
+ tryComplete: if (result == null) {
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ if (s instanceof AltResult) {
+ if ((x = ((AltResult)s).ex) != null) {
+ completeThrowable(x, s);
+ break tryComplete;
+ }
+ s = null;
+ }
+ try {
+ if (c != null && !c.claim())
+ return false;
+ @SuppressWarnings("unchecked") R rr = (R) r;
+ @SuppressWarnings("unchecked") S ss = (S) s;
+ f.accept(rr, ss);
+ completeNull();
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private <U> CompletableFuture<Void> biAcceptStage(
+ Executor e, CompletionStage<U> o,
+ BiConsumer<? super T,? super U> f) {
+ CompletableFuture<U> b;
+ if (f == null || (b = o.toCompletableFuture()) == null)
+ throw new NullPointerException();
+ CompletableFuture<Void> d = new CompletableFuture<Void>();
+ if (e != null || !d.biAccept(this, b, f, null)) {
+ BiAccept<T,U> c = new BiAccept<T,U>(e, d, this, b, f);
+ bipush(b, c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
- /** Number of processors, for spin control */
- static final int NCPU = Runtime.getRuntime().availableProcessors();
+ @SuppressWarnings("serial")
+ static final class BiRun<T,U> extends BiCompletion<T,U,Void> {
+ Runnable fn;
+ BiRun(Executor executor, CompletableFuture<Void> dep,
+ CompletableFuture<T> src,
+ CompletableFuture<U> snd,
+ Runnable fn) {
+ super(executor, dep, src, snd); this.fn = fn;
+ }
+ final CompletableFuture<Void> tryFire(int mode) {
+ CompletableFuture<Void> d;
+ CompletableFuture<T> a;
+ CompletableFuture<U> b;
+ if ((d = dep) == null ||
+ !d.biRun(a = src, b = snd, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; snd = null; fn = null;
+ return d.postFire(a, b, mode);
+ }
+ }
+
+ final boolean biRun(CompletableFuture<?> a, CompletableFuture<?> b,
+ Runnable f, BiRun<?,?> c) {
+ Object r, s; Throwable x;
+ if (a == null || (r = a.result) == null ||
+ b == null || (s = b.result) == null || f == null)
+ return false;
+ if (result == null) {
+ if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+ completeThrowable(x, r);
+ else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
+ completeThrowable(x, s);
+ else
+ try {
+ if (c != null && !c.claim())
+ return false;
+ f.run();
+ completeNull();
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private CompletableFuture<Void> biRunStage(Executor e, CompletionStage<?> o,
+ Runnable f) {
+ CompletableFuture<?> b;
+ if (f == null || (b = o.toCompletableFuture()) == null)
+ throw new NullPointerException();
+ CompletableFuture<Void> d = new CompletableFuture<Void>();
+ if (e != null || !d.biRun(this, b, f, null)) {
+ BiRun<T,?> c = new BiRun<>(e, d, this, b, f);
+ bipush(b, c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class BiRelay<T,U> extends BiCompletion<T,U,Void> { // for And
+ BiRelay(CompletableFuture<Void> dep,
+ CompletableFuture<T> src,
+ CompletableFuture<U> snd) {
+ super(null, dep, src, snd);
+ }
+ final CompletableFuture<Void> tryFire(int mode) {
+ CompletableFuture<Void> d;
+ CompletableFuture<T> a;
+ CompletableFuture<U> b;
+ if ((d = dep) == null || !d.biRelay(a = src, b = snd))
+ return null;
+ src = null; snd = null; dep = null;
+ return d.postFire(a, b, mode);
+ }
+ }
+
+ boolean biRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
+ Object r, s; Throwable x;
+ if (a == null || (r = a.result) == null ||
+ b == null || (s = b.result) == null)
+ return false;
+ if (result == null) {
+ if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+ completeThrowable(x, r);
+ else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
+ completeThrowable(x, s);
+ else
+ completeNull();
+ }
+ return true;
+ }
+
+ /** Recursively constructs a tree of completions. */
+ static CompletableFuture<Void> andTree(CompletableFuture<?>[] cfs,
+ int lo, int hi) {
+ CompletableFuture<Void> d = new CompletableFuture<Void>();
+ if (lo > hi) // empty
+ d.result = NIL;
+ else {
+ CompletableFuture<?> a, b;
+ int mid = (lo + hi) >>> 1;
+ if ((a = (lo == mid ? cfs[lo] :
+ andTree(cfs, lo, mid))) == null ||
+ (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
+ andTree(cfs, mid+1, hi))) == null)
+ throw new NullPointerException();
+ if (!d.biRelay(a, b)) {
+ BiRelay<?,?> c = new BiRelay<>(d, a, b);
+ a.bipush(b, c);
+ c.tryFire(SYNC);
+ }
+ }
+ return d;
+ }
+
+ /* ------------- Projected (Ored) BiCompletions -------------- */
+
+ /** Pushes completion to this and b unless either done. */
+ final void orpush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
+ if (c != null) {
+ while ((b == null || b.result == null) && result == null) {
+ if (tryPushStack(c)) {
+ if (b != null && b != this && b.result == null) {
+ Completion q = new CoCompletion(c);
+ while (result == null && b.result == null &&
+ !b.tryPushStack(q))
+ lazySetNext(q, null); // clear on failure
+ }
+ break;
+ }
+ lazySetNext(c, null); // clear on failure
+ }
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class OrApply<T,U extends T,V> extends BiCompletion<T,U,V> {
+ Function<? super T,? extends V> fn;
+ OrApply(Executor executor, CompletableFuture<V> dep,
+ CompletableFuture<T> src,
+ CompletableFuture<U> snd,
+ Function<? super T,? extends V> fn) {
+ super(executor, dep, src, snd); this.fn = fn;
+ }
+ final CompletableFuture<V> tryFire(int mode) {
+ CompletableFuture<V> d;
+ CompletableFuture<T> a;
+ CompletableFuture<U> b;
+ if ((d = dep) == null ||
+ !d.orApply(a = src, b = snd, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; snd = null; fn = null;
+ return d.postFire(a, b, mode);
+ }
+ }
- /**
- * Heuristic spin value for waitingGet() before blocking on
- * multiprocessors
- */
- static final int SPINS = (NCPU > 1) ? 1 << 8 : 0;
+ final <R,S extends R> boolean orApply(CompletableFuture<R> a,
+ CompletableFuture<S> b,
+ Function<? super R, ? extends T> f,
+ OrApply<R,S,T> c) {
+ Object r; Throwable x;
+ if (a == null || b == null ||
+ ((r = a.result) == null && (r = b.result) == null) || f == null)
+ return false;
+ tryComplete: if (result == null) {
+ try {
+ if (c != null && !c.claim())
+ return false;
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ @SuppressWarnings("unchecked") R rr = (R) r;
+ completeValue(f.apply(rr));
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private <U extends T,V> CompletableFuture<V> orApplyStage(
+ Executor e, CompletionStage<U> o,
+ Function<? super T, ? extends V> f) {
+ CompletableFuture<U> b;
+ if (f == null || (b = o.toCompletableFuture()) == null)
+ throw new NullPointerException();
+ CompletableFuture<V> d = new CompletableFuture<V>();
+ if (e != null || !d.orApply(this, b, f, null)) {
+ OrApply<T,U,V> c = new OrApply<T,U,V>(e, d, this, b, f);
+ orpush(b, c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class OrAccept<T,U extends T> extends BiCompletion<T,U,Void> {
+ Consumer<? super T> fn;
+ OrAccept(Executor executor, CompletableFuture<Void> dep,
+ CompletableFuture<T> src,
+ CompletableFuture<U> snd,
+ Consumer<? super T> fn) {
+ super(executor, dep, src, snd); this.fn = fn;
+ }
+ final CompletableFuture<Void> tryFire(int mode) {
+ CompletableFuture<Void> d;
+ CompletableFuture<T> a;
+ CompletableFuture<U> b;
+ if ((d = dep) == null ||
+ !d.orAccept(a = src, b = snd, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; snd = null; fn = null;
+ return d.postFire(a, b, mode);
+ }
+ }
+
+ final <R,S extends R> boolean orAccept(CompletableFuture<R> a,
+ CompletableFuture<S> b,
+ Consumer<? super R> f,
+ OrAccept<R,S> c) {
+ Object r; Throwable x;
+ if (a == null || b == null ||
+ ((r = a.result) == null && (r = b.result) == null) || f == null)
+ return false;
+ tryComplete: if (result == null) {
+ try {
+ if (c != null && !c.claim())
+ return false;
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ @SuppressWarnings("unchecked") R rr = (R) r;
+ f.accept(rr);
+ completeNull();
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private <U extends T> CompletableFuture<Void> orAcceptStage(
+ Executor e, CompletionStage<U> o, Consumer<? super T> f) {
+ CompletableFuture<U> b;
+ if (f == null || (b = o.toCompletableFuture()) == null)
+ throw new NullPointerException();
+ CompletableFuture<Void> d = new CompletableFuture<Void>();
+ if (e != null || !d.orAccept(this, b, f, null)) {
+ OrAccept<T,U> c = new OrAccept<T,U>(e, d, this, b, f);
+ orpush(b, c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class OrRun<T,U> extends BiCompletion<T,U,Void> {
+ Runnable fn;
+ OrRun(Executor executor, CompletableFuture<Void> dep,
+ CompletableFuture<T> src,
+ CompletableFuture<U> snd,
+ Runnable fn) {
+ super(executor, dep, src, snd); this.fn = fn;
+ }
+ final CompletableFuture<Void> tryFire(int mode) {
+ CompletableFuture<Void> d;
+ CompletableFuture<T> a;
+ CompletableFuture<U> b;
+ if ((d = dep) == null ||
+ !d.orRun(a = src, b = snd, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; snd = null; fn = null;
+ return d.postFire(a, b, mode);
+ }
+ }
+
+ final boolean orRun(CompletableFuture<?> a, CompletableFuture<?> b,
+ Runnable f, OrRun<?,?> c) {
+ Object r; Throwable x;
+ if (a == null || b == null ||
+ ((r = a.result) == null && (r = b.result) == null) || f == null)
+ return false;
+ if (result == null) {
+ try {
+ if (c != null && !c.claim())
+ return false;
+ if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+ completeThrowable(x, r);
+ else {
+ f.run();
+ completeNull();
+ }
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private CompletableFuture<Void> orRunStage(Executor e, CompletionStage<?> o,
+ Runnable f) {
+ CompletableFuture<?> b;
+ if (f == null || (b = o.toCompletableFuture()) == null)
+ throw new NullPointerException();
+ CompletableFuture<Void> d = new CompletableFuture<Void>();
+ if (e != null || !d.orRun(this, b, f, null)) {
+ OrRun<T,?> c = new OrRun<>(e, d, this, b, f);
+ orpush(b, c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class OrRelay<T,U> extends BiCompletion<T,U,Object> { // for Or
+ OrRelay(CompletableFuture<Object> dep, CompletableFuture<T> src,
+ CompletableFuture<U> snd) {
+ super(null, dep, src, snd);
+ }
+ final CompletableFuture<Object> tryFire(int mode) {
+ CompletableFuture<Object> d;
+ CompletableFuture<T> a;
+ CompletableFuture<U> b;
+ if ((d = dep) == null || !d.orRelay(a = src, b = snd))
+ return null;
+ src = null; snd = null; dep = null;
+ return d.postFire(a, b, mode);
+ }
+ }
+
+ final boolean orRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
+ Object r;
+ if (a == null || b == null ||
+ ((r = a.result) == null && (r = b.result) == null))
+ return false;
+ if (result == null)
+ completeRelay(r);
+ return true;
+ }
+
+ /** Recursively constructs a tree of completions. */
+ static CompletableFuture<Object> orTree(CompletableFuture<?>[] cfs,
+ int lo, int hi) {
+ CompletableFuture<Object> d = new CompletableFuture<Object>();
+ if (lo <= hi) {
+ CompletableFuture<?> a, b;
+ int mid = (lo + hi) >>> 1;
+ if ((a = (lo == mid ? cfs[lo] :
+ orTree(cfs, lo, mid))) == null ||
+ (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
+ orTree(cfs, mid+1, hi))) == null)
+ throw new NullPointerException();
+ if (!d.orRelay(a, b)) {
+ OrRelay<?,?> c = new OrRelay<>(d, a, b);
+ a.orpush(b, c);
+ c.tryFire(SYNC);
+ }
+ }
+ return d;
+ }
+
+ /* ------------- Zero-input Async forms -------------- */
+
+ @SuppressWarnings("serial")
+ static final class AsyncSupply<T> extends ForkJoinTask<Void>
+ implements Runnable, AsynchronousCompletionTask {
+ CompletableFuture<T> dep; Supplier<T> fn;
+ AsyncSupply(CompletableFuture<T> dep, Supplier<T> fn) {
+ this.dep = dep; this.fn = fn;
+ }
+
+ public final Void getRawResult() { return null; }
+ public final void setRawResult(Void v) {}
+ public final boolean exec() { run(); return true; }
+
+ public void run() {
+ CompletableFuture<T> d; Supplier<T> f;
+ if ((d = dep) != null && (f = fn) != null) {
+ dep = null; fn = null;
+ if (d.result == null) {
+ try {
+ d.completeValue(f.get());
+ } catch (Throwable ex) {
+ d.completeThrowable(ex);
+ }
+ }
+ d.postComplete();
+ }
+ }
+ }
+
+ static <U> CompletableFuture<U> asyncSupplyStage(Executor e,
+ Supplier<U> f) {
+ if (f == null) throw new NullPointerException();
+ CompletableFuture<U> d = new CompletableFuture<U>();
+ e.execute(new AsyncSupply<U>(d, f));
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class AsyncRun extends ForkJoinTask<Void>
+ implements Runnable, AsynchronousCompletionTask {
+ CompletableFuture<Void> dep; Runnable fn;
+ AsyncRun(CompletableFuture<Void> dep, Runnable fn) {
+ this.dep = dep; this.fn = fn;
+ }
+
+ public final Void getRawResult() { return null; }
+ public final void setRawResult(Void v) {}
+ public final boolean exec() { run(); return true; }
+
+ public void run() {
+ CompletableFuture<Void> d; Runnable f;
+ if ((d = dep) != null && (f = fn) != null) {
+ dep = null; fn = null;
+ if (d.result == null) {
+ try {
+ f.run();
+ d.completeNull();
+ } catch (Throwable ex) {
+ d.completeThrowable(ex);
+ }
+ }
+ d.postComplete();
+ }
+ }
+ }
+
+ static CompletableFuture<Void> asyncRunStage(Executor e, Runnable f) {
+ if (f == null) throw new NullPointerException();
+ CompletableFuture<Void> d = new CompletableFuture<Void>();
+ e.execute(new AsyncRun(d, f));
+ return d;
+ }
+
+ /* ------------- Signallers -------------- */
/**
- * Linked nodes to record waiting threads in a Treiber stack. See
- * other classes such as Phaser and SynchronousQueue for more
- * detailed explanation. This class implements ManagedBlocker to
- * avoid starvation when blocking actions pile up in
- * ForkJoinPools.
+ * Completion for recording and releasing a waiting thread. This
+ * class implements ManagedBlocker to avoid starvation when
+ * blocking actions pile up in ForkJoinPools.
*/
- static final class WaitNode implements ForkJoinPool.ManagedBlocker {
- long nanos; // wait time if timed
- final long deadline; // non-zero if timed
+ @SuppressWarnings("serial")
+ static final class Signaller extends Completion
+ implements ForkJoinPool.ManagedBlocker {
+ long nanos; // wait time if timed
+ final long deadline; // non-zero if timed
volatile int interruptControl; // > 0: interruptible, < 0: interrupted
volatile Thread thread;
- volatile WaitNode next;
- WaitNode(boolean interruptible, long nanos, long deadline) {
+
+ Signaller(boolean interruptible, long nanos, long deadline) {
this.thread = Thread.currentThread();
this.interruptControl = interruptible ? 1 : 0;
this.nanos = nanos;
this.deadline = deadline;
}
+ final CompletableFuture<?> tryFire(int ignore) {
+ Thread w; // no need to atomically claim
+ if ((w = thread) != null) {
+ thread = null;
+ LockSupport.unpark(w);
+ }
+ return null;
+ }
public boolean isReleasable() {
if (thread == null)
return true;
@@ -273,6 +1687,7 @@
LockSupport.parkNanos(this, nanos);
return isReleasable();
}
+ final boolean isLive() { return thread != null; }
}
/**
@@ -280,1832 +1695,89 @@
* interrupted.
*/
private Object waitingGet(boolean interruptible) {
- WaitNode q = null;
+ Signaller q = null;
boolean queued = false;
- int spins = SPINS;
- for (Object r;;) {
- if ((r = result) != null) {
- if (q != null) { // suppress unpark
- q.thread = null;
- if (q.interruptControl < 0) {
- if (interruptible) {
- removeWaiter(q);
- return null;
- }
- Thread.currentThread().interrupt();
- }
- }
- postComplete(); // help release others
- return r;
- }
+ int spins = -1;
+ Object r;
+ while ((r = result) == null) {
+ if (spins < 0)
+ spins = (Runtime.getRuntime().availableProcessors() > 1) ?
+ 1 << 8 : 0; // Use brief spin-wait on multiprocessors
else if (spins > 0) {
- int rnd = ThreadLocalRandom.nextSecondarySeed();
- if (rnd == 0)
- rnd = ThreadLocalRandom.current().nextInt();
- if (rnd >= 0)
+ if (ThreadLocalRandom.nextSecondarySeed() >= 0)
--spins;
}
else if (q == null)
- q = new WaitNode(interruptible, 0L, 0L);
+ q = new Signaller(interruptible, 0L, 0L);
else if (!queued)
- queued = UNSAFE.compareAndSwapObject(this, WAITERS,
- q.next = waiters, q);
+ queued = tryPushStack(q);
else if (interruptible && q.interruptControl < 0) {
- removeWaiter(q);
+ q.thread = null;
+ cleanStack();
return null;
}
else if (q.thread != null && result == null) {
try {
ForkJoinPool.managedBlock(q);
- } catch (InterruptedException ex) {
- q.interruptControl = -1;
- }
- }
- }
- }
-
- /**
- * Awaits completion or aborts on interrupt or timeout.
- *
- * @param nanos time to wait
- * @return raw result
- */
- private Object timedAwaitDone(long nanos)
- throws InterruptedException, TimeoutException {
- WaitNode q = null;
- boolean queued = false;
- for (Object r;;) {
- if ((r = result) != null) {
- if (q != null) {
- q.thread = null;
- if (q.interruptControl < 0) {
- removeWaiter(q);
- throw new InterruptedException();
- }
- }
- postComplete();
- return r;
- }
- else if (q == null) {
- if (nanos <= 0L)
- throw new TimeoutException();
- long d = System.nanoTime() + nanos;
- q = new WaitNode(true, nanos, d == 0L ? 1L : d); // avoid 0
- }
- else if (!queued)
- queued = UNSAFE.compareAndSwapObject(this, WAITERS,
- q.next = waiters, q);
- else if (q.interruptControl < 0) {
- removeWaiter(q);
- throw new InterruptedException();
- }
- else if (q.nanos <= 0L) {
- if (result == null) {
- removeWaiter(q);
- throw new TimeoutException();
- }
- }
- else if (q.thread != null && result == null) {
- try {
- ForkJoinPool.managedBlock(q);
- } catch (InterruptedException ex) {
+ } catch (InterruptedException ie) {
q.interruptControl = -1;
}
}
}
- }
-
- /**
- * Tries to unlink a timed-out or interrupted wait node to avoid
- * accumulating garbage. Internal nodes are simply unspliced
- * without CAS since it is harmless if they are traversed anyway
- * by releasers. To avoid effects of unsplicing from already
- * removed nodes, the list is retraversed in case of an apparent
- * race. This is slow when there are a lot of nodes, but we don't
- * expect lists to be long enough to outweigh higher-overhead
- * schemes.
- */
- private void removeWaiter(WaitNode node) {
- if (node != null) {
- node.thread = null;
- retry:
- for (;;) { // restart on removeWaiter race
- for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
- s = q.next;
- if (q.thread != null)
- pred = q;
- else if (pred != null) {
- pred.next = s;
- if (pred.thread == null) // check for race
- continue retry;
- }
- else if (!UNSAFE.compareAndSwapObject(this, WAITERS, q, s))
- continue retry;
- }
- break;
+ if (q != null) {
+ q.thread = null;
+ if (q.interruptControl < 0) {
+ if (interruptible)
+ r = null; // report interruption
+ else
+ Thread.currentThread().interrupt();
}
}
- }
-
- /* ------------- Async tasks -------------- */
-
- /**
- * A marker interface identifying asynchronous tasks produced by
- * {@code async} methods. This may be useful for monitoring,
- * debugging, and tracking asynchronous activities.
- *
- * @since 1.8
- */
- public static interface AsynchronousCompletionTask {
- }
-
- /** Base class can act as either FJ or plain Runnable */
- @SuppressWarnings("serial")
- abstract static class Async extends ForkJoinTask<Void>
- implements Runnable, AsynchronousCompletionTask {
- public final Void getRawResult() { return null; }
- public final void setRawResult(Void v) { }
- public final void run() { exec(); }
+ postComplete();
+ return r;
}
/**
- * Starts the given async task using the given executor, unless
- * the executor is ForkJoinPool.commonPool and it has been
- * disabled, in which case starts a new thread.
- */
- static void execAsync(Executor e, Async r) {
- if (e == ForkJoinPool.commonPool() &&
- ForkJoinPool.getCommonPoolParallelism() <= 1)
- new Thread(r).start();
- else
- e.execute(r);
- }
-
- static final class AsyncRun extends Async {
- final Runnable fn;
- final CompletableFuture<Void> dst;
- AsyncRun(Runnable fn, CompletableFuture<Void> dst) {
- this.fn = fn; this.dst = dst;
- }
- public final boolean exec() {
- CompletableFuture<Void> d; Throwable ex;
- if ((d = this.dst) != null && d.result == null) {
- try {
- fn.run();
- ex = null;
- } catch (Throwable rex) {
- ex = rex;
- }
- d.internalComplete(null, ex);
- }
- return true;
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class AsyncSupply<U> extends Async {
- final Supplier<U> fn;
- final CompletableFuture<U> dst;
- AsyncSupply(Supplier<U> fn, CompletableFuture<U> dst) {
- this.fn = fn; this.dst = dst;
- }
- public final boolean exec() {
- CompletableFuture<U> d; U u; Throwable ex;
- if ((d = this.dst) != null && d.result == null) {
- try {
- u = fn.get();
- ex = null;
- } catch (Throwable rex) {
- ex = rex;
- u = null;
- }
- d.internalComplete(u, ex);
- }
- return true;
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class AsyncApply<T,U> extends Async {
- final T arg;
- final Function<? super T,? extends U> fn;
- final CompletableFuture<U> dst;
- AsyncApply(T arg, Function<? super T,? extends U> fn,
- CompletableFuture<U> dst) {
- this.arg = arg; this.fn = fn; this.dst = dst;
- }
- public final boolean exec() {
- CompletableFuture<U> d; U u; Throwable ex;
- if ((d = this.dst) != null && d.result == null) {
- try {
- u = fn.apply(arg);
- ex = null;
- } catch (Throwable rex) {
- ex = rex;
- u = null;
- }
- d.internalComplete(u, ex);
- }
- return true;
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class AsyncCombine<T,U,V> extends Async {
- final T arg1;
- final U arg2;
- final BiFunction<? super T,? super U,? extends V> fn;
- final CompletableFuture<V> dst;
- AsyncCombine(T arg1, U arg2,
- BiFunction<? super T,? super U,? extends V> fn,
- CompletableFuture<V> dst) {
- this.arg1 = arg1; this.arg2 = arg2; this.fn = fn; this.dst = dst;
- }
- public final boolean exec() {
- CompletableFuture<V> d; V v; Throwable ex;
- if ((d = this.dst) != null && d.result == null) {
- try {
- v = fn.apply(arg1, arg2);
- ex = null;
- } catch (Throwable rex) {
- ex = rex;
- v = null;
- }
- d.internalComplete(v, ex);
- }
- return true;
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class AsyncAccept<T> extends Async {
- final T arg;
- final Consumer<? super T> fn;
- final CompletableFuture<?> dst;
- AsyncAccept(T arg, Consumer<? super T> fn,
- CompletableFuture<?> dst) {
- this.arg = arg; this.fn = fn; this.dst = dst;
- }
- public final boolean exec() {
- CompletableFuture<?> d; Throwable ex;
- if ((d = this.dst) != null && d.result == null) {
- try {
- fn.accept(arg);
- ex = null;
- } catch (Throwable rex) {
- ex = rex;
- }
- d.internalComplete(null, ex);
- }
- return true;
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class AsyncAcceptBoth<T,U> extends Async {
- final T arg1;
- final U arg2;
- final BiConsumer<? super T,? super U> fn;
- final CompletableFuture<?> dst;
- AsyncAcceptBoth(T arg1, U arg2,
- BiConsumer<? super T,? super U> fn,
- CompletableFuture<?> dst) {
- this.arg1 = arg1; this.arg2 = arg2; this.fn = fn; this.dst = dst;
- }
- public final boolean exec() {
- CompletableFuture<?> d; Throwable ex;
- if ((d = this.dst) != null && d.result == null) {
- try {
- fn.accept(arg1, arg2);
- ex = null;
- } catch (Throwable rex) {
- ex = rex;
- }
- d.internalComplete(null, ex);
- }
- return true;
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class AsyncCompose<T,U> extends Async {
- final T arg;
- final Function<? super T, ? extends CompletionStage<U>> fn;
- final CompletableFuture<U> dst;
- AsyncCompose(T arg,
- Function<? super T, ? extends CompletionStage<U>> fn,
- CompletableFuture<U> dst) {
- this.arg = arg; this.fn = fn; this.dst = dst;
- }
- public final boolean exec() {
- CompletableFuture<U> d, fr; U u; Throwable ex;
- if ((d = this.dst) != null && d.result == null) {
- try {
- CompletionStage<U> cs = fn.apply(arg);
- fr = (cs == null) ? null : cs.toCompletableFuture();
- ex = (fr == null) ? new NullPointerException() : null;
- } catch (Throwable rex) {
- ex = rex;
- fr = null;
- }
- if (ex != null)
- u = null;
- else {
- Object r = fr.result;
- if (r == null)
- r = fr.waitingGet(false);
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- u = null;
- }
- else {
- @SuppressWarnings("unchecked") U ur = (U) r;
- u = ur;
- }
- }
- d.internalComplete(u, ex);
- }
- return true;
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class AsyncWhenComplete<T> extends Async {
- final T arg1;
- final Throwable arg2;
- final BiConsumer<? super T,? super Throwable> fn;
- final CompletableFuture<T> dst;
- AsyncWhenComplete(T arg1, Throwable arg2,
- BiConsumer<? super T,? super Throwable> fn,
- CompletableFuture<T> dst) {
- this.arg1 = arg1; this.arg2 = arg2; this.fn = fn; this.dst = dst;
- }
- public final boolean exec() {
- CompletableFuture<T> d;
- if ((d = this.dst) != null && d.result == null) {
- Throwable ex = arg2;
- try {
- fn.accept(arg1, ex);
- } catch (Throwable rex) {
- if (ex == null)
- ex = rex;
- }
- d.internalComplete(arg1, ex);
- }
- return true;
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- /* ------------- Completions -------------- */
-
- /**
- * Simple linked list nodes to record completions, used in
- * basically the same way as WaitNodes. (We separate nodes from
- * the Completions themselves mainly because for the And and Or
- * methods, the same Completion object resides in two lists.)
+ * Returns raw result after waiting, or null if interrupted, or
+ * throws TimeoutException on timeout.
*/
- static final class CompletionNode {
- final Completion completion;
- volatile CompletionNode next;
- CompletionNode(Completion completion) { this.completion = completion; }
- }
-
- // Opportunistically subclass AtomicInteger to use compareAndSet to claim.
- @SuppressWarnings("serial")
- abstract static class Completion extends AtomicInteger implements Runnable {
- }
-
- static final class ThenApply<T,U> extends Completion {
- final CompletableFuture<? extends T> src;
- final Function<? super T,? extends U> fn;
- final CompletableFuture<U> dst;
- final Executor executor;
- ThenApply(CompletableFuture<? extends T> src,
- Function<? super T,? extends U> fn,
- CompletableFuture<U> dst,
- Executor executor) {
- this.src = src; this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final Function<? super T,? extends U> fn;
- final CompletableFuture<U> dst;
- Object r; T t; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- Executor e = executor;
- U u = null;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncApply<T,U>(t, fn, dst));
- else
- u = fn.apply(t);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(u, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class ThenAccept<T> extends Completion {
- final CompletableFuture<? extends T> src;
- final Consumer<? super T> fn;
- final CompletableFuture<?> dst;
- final Executor executor;
- ThenAccept(CompletableFuture<? extends T> src,
- Consumer<? super T> fn,
- CompletableFuture<?> dst,
- Executor executor) {
- this.src = src; this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final Consumer<? super T> fn;
- final CompletableFuture<?> dst;
- Object r; T t; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- Executor e = executor;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncAccept<T>(t, fn, dst));
- else
- fn.accept(t);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class ThenRun extends Completion {
- final CompletableFuture<?> src;
- final Runnable fn;
- final CompletableFuture<Void> dst;
- final Executor executor;
- ThenRun(CompletableFuture<?> src,
- Runnable fn,
- CompletableFuture<Void> dst,
- Executor executor) {
- this.src = src; this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<?> a;
- final Runnable fn;
- final CompletableFuture<Void> dst;
- Object r; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult)
- ex = ((AltResult)r).ex;
- else
- ex = null;
- Executor e = executor;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncRun(fn, dst));
- else
- fn.run();
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class ThenCombine<T,U,V> extends Completion {
- final CompletableFuture<? extends T> src;
- final CompletableFuture<? extends U> snd;
- final BiFunction<? super T,? super U,? extends V> fn;
- final CompletableFuture<V> dst;
- final Executor executor;
- ThenCombine(CompletableFuture<? extends T> src,
- CompletableFuture<? extends U> snd,
- BiFunction<? super T,? super U,? extends V> fn,
- CompletableFuture<V> dst,
- Executor executor) {
- this.src = src; this.snd = snd;
- this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final CompletableFuture<? extends U> b;
- final BiFunction<? super T,? super U,? extends V> fn;
- final CompletableFuture<V> dst;
- Object r, s; T t; U u; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- (b = this.snd) != null &&
- (s = b.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- if (ex != null)
- u = null;
- else if (s instanceof AltResult) {
- ex = ((AltResult)s).ex;
- u = null;
- }
- else {
- @SuppressWarnings("unchecked") U us = (U) s;
- u = us;
- }
- Executor e = executor;
- V v = null;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncCombine<T,U,V>(t, u, fn, dst));
- else
- v = fn.apply(t, u);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(v, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class ThenAcceptBoth<T,U> extends Completion {
- final CompletableFuture<? extends T> src;
- final CompletableFuture<? extends U> snd;
- final BiConsumer<? super T,? super U> fn;
- final CompletableFuture<Void> dst;
- final Executor executor;
- ThenAcceptBoth(CompletableFuture<? extends T> src,
- CompletableFuture<? extends U> snd,
- BiConsumer<? super T,? super U> fn,
- CompletableFuture<Void> dst,
- Executor executor) {
- this.src = src; this.snd = snd;
- this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final CompletableFuture<? extends U> b;
- final BiConsumer<? super T,? super U> fn;
- final CompletableFuture<Void> dst;
- Object r, s; T t; U u; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- (b = this.snd) != null &&
- (s = b.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- if (ex != null)
- u = null;
- else if (s instanceof AltResult) {
- ex = ((AltResult)s).ex;
- u = null;
- }
- else {
- @SuppressWarnings("unchecked") U us = (U) s;
- u = us;
- }
- Executor e = executor;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncAcceptBoth<T,U>(t, u, fn, dst));
- else
- fn.accept(t, u);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class RunAfterBoth extends Completion {
- final CompletableFuture<?> src;
- final CompletableFuture<?> snd;
- final Runnable fn;
- final CompletableFuture<Void> dst;
- final Executor executor;
- RunAfterBoth(CompletableFuture<?> src,
- CompletableFuture<?> snd,
- Runnable fn,
- CompletableFuture<Void> dst,
- Executor executor) {
- this.src = src; this.snd = snd;
- this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<?> a;
- final CompletableFuture<?> b;
- final Runnable fn;
- final CompletableFuture<Void> dst;
- Object r, s; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- (b = this.snd) != null &&
- (s = b.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult)
- ex = ((AltResult)r).ex;
- else
- ex = null;
- if (ex == null && (s instanceof AltResult))
- ex = ((AltResult)s).ex;
- Executor e = executor;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncRun(fn, dst));
- else
- fn.run();
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class AndCompletion extends Completion {
- final CompletableFuture<?> src;
- final CompletableFuture<?> snd;
- final CompletableFuture<Void> dst;
- AndCompletion(CompletableFuture<?> src,
- CompletableFuture<?> snd,
- CompletableFuture<Void> dst) {
- this.src = src; this.snd = snd; this.dst = dst;
- }
- public final void run() {
- final CompletableFuture<?> a;
- final CompletableFuture<?> b;
- final CompletableFuture<Void> dst;
- Object r, s; Throwable ex;
- if ((dst = this.dst) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- (b = this.snd) != null &&
- (s = b.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult)
- ex = ((AltResult)r).ex;
- else
- ex = null;
- if (ex == null && (s instanceof AltResult))
- ex = ((AltResult)s).ex;
- dst.internalComplete(null, ex);
+ private Object timedGet(long nanos) throws TimeoutException {
+ if (Thread.interrupted())
+ return null;
+ if (nanos <= 0L)
+ throw new TimeoutException();
+ long d = System.nanoTime() + nanos;
+ Signaller q = new Signaller(true, nanos, d == 0L ? 1L : d); // avoid 0
+ boolean queued = false;
+ Object r;
+ // We intentionally don't spin here (as waitingGet does) because
+ // the call to nanoTime() above acts much like a spin.
+ while ((r = result) == null) {
+ if (!queued)
+ queued = tryPushStack(q);
+ else if (q.interruptControl < 0 || q.nanos <= 0L) {
+ q.thread = null;
+ cleanStack();
+ if (q.interruptControl < 0)
+ return null;
+ throw new TimeoutException();
}
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class ApplyToEither<T,U> extends Completion {
- final CompletableFuture<? extends T> src;
- final CompletableFuture<? extends T> snd;
- final Function<? super T,? extends U> fn;
- final CompletableFuture<U> dst;
- final Executor executor;
- ApplyToEither(CompletableFuture<? extends T> src,
- CompletableFuture<? extends T> snd,
- Function<? super T,? extends U> fn,
- CompletableFuture<U> dst,
- Executor executor) {
- this.src = src; this.snd = snd;
- this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final CompletableFuture<? extends T> b;
- final Function<? super T,? extends U> fn;
- final CompletableFuture<U> dst;
- Object r; T t; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (((a = this.src) != null && (r = a.result) != null) ||
- ((b = this.snd) != null && (r = b.result) != null)) &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- Executor e = executor;
- U u = null;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncApply<T,U>(t, fn, dst));
- else
- u = fn.apply(t);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(u, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class AcceptEither<T> extends Completion {
- final CompletableFuture<? extends T> src;
- final CompletableFuture<? extends T> snd;
- final Consumer<? super T> fn;
- final CompletableFuture<Void> dst;
- final Executor executor;
- AcceptEither(CompletableFuture<? extends T> src,
- CompletableFuture<? extends T> snd,
- Consumer<? super T> fn,
- CompletableFuture<Void> dst,
- Executor executor) {
- this.src = src; this.snd = snd;
- this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final CompletableFuture<? extends T> b;
- final Consumer<? super T> fn;
- final CompletableFuture<Void> dst;
- Object r; T t; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (((a = this.src) != null && (r = a.result) != null) ||
- ((b = this.snd) != null && (r = b.result) != null)) &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- Executor e = executor;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncAccept<T>(t, fn, dst));
- else
- fn.accept(t);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class RunAfterEither extends Completion {
- final CompletableFuture<?> src;
- final CompletableFuture<?> snd;
- final Runnable fn;
- final CompletableFuture<Void> dst;
- final Executor executor;
- RunAfterEither(CompletableFuture<?> src,
- CompletableFuture<?> snd,
- Runnable fn,
- CompletableFuture<Void> dst,
- Executor executor) {
- this.src = src; this.snd = snd;
- this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<?> a;
- final CompletableFuture<?> b;
- final Runnable fn;
- final CompletableFuture<Void> dst;
- Object r; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (((a = this.src) != null && (r = a.result) != null) ||
- ((b = this.snd) != null && (r = b.result) != null)) &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult)
- ex = ((AltResult)r).ex;
- else
- ex = null;
- Executor e = executor;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncRun(fn, dst));
- else
- fn.run();
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class OrCompletion extends Completion {
- final CompletableFuture<?> src;
- final CompletableFuture<?> snd;
- final CompletableFuture<Object> dst;
- OrCompletion(CompletableFuture<?> src,
- CompletableFuture<?> snd,
- CompletableFuture<Object> dst) {
- this.src = src; this.snd = snd; this.dst = dst;
- }
- public final void run() {
- final CompletableFuture<?> a;
- final CompletableFuture<?> b;
- final CompletableFuture<Object> dst;
- Object r, t; Throwable ex;
- if ((dst = this.dst) != null &&
- (((a = this.src) != null && (r = a.result) != null) ||
- ((b = this.snd) != null && (r = b.result) != null)) &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- t = r;
- }
- dst.internalComplete(t, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class ExceptionCompletion<T> extends Completion {
- final CompletableFuture<? extends T> src;
- final Function<? super Throwable, ? extends T> fn;
- final CompletableFuture<T> dst;
- ExceptionCompletion(CompletableFuture<? extends T> src,
- Function<? super Throwable, ? extends T> fn,
- CompletableFuture<T> dst) {
- this.src = src; this.fn = fn; this.dst = dst;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final Function<? super Throwable, ? extends T> fn;
- final CompletableFuture<T> dst;
- Object r; T t = null; Throwable ex, dx = null;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- compareAndSet(0, 1)) {
- if ((r instanceof AltResult) &&
- (ex = ((AltResult)r).ex) != null) {
- try {
- t = fn.apply(ex);
- } catch (Throwable rex) {
- dx = rex;
- }
- }
- else {
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- dst.internalComplete(t, dx);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class WhenCompleteCompletion<T> extends Completion {
- final CompletableFuture<? extends T> src;
- final BiConsumer<? super T, ? super Throwable> fn;
- final CompletableFuture<T> dst;
- final Executor executor;
- WhenCompleteCompletion(CompletableFuture<? extends T> src,
- BiConsumer<? super T, ? super Throwable> fn,
- CompletableFuture<T> dst,
- Executor executor) {
- this.src = src; this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final BiConsumer<? super T, ? super Throwable> fn;
- final CompletableFuture<T> dst;
- Object r; T t; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- Executor e = executor;
- Throwable dx = null;
+ else if (q.thread != null && result == null) {
try {
- if (e != null)
- execAsync(e, new AsyncWhenComplete<T>(t, ex, fn, dst));
- else
- fn.accept(t, ex);
- } catch (Throwable rex) {
- dx = rex;
- }
- if (e == null || dx != null)
- dst.internalComplete(t, ex != null ? ex : dx);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class ThenCopy<T> extends Completion {
- final CompletableFuture<?> src;
- final CompletableFuture<T> dst;
- ThenCopy(CompletableFuture<?> src,
- CompletableFuture<T> dst) {
- this.src = src; this.dst = dst;
- }
- public final void run() {
- final CompletableFuture<?> a;
- final CompletableFuture<T> dst;
- Object r; T t; Throwable ex;
- if ((dst = this.dst) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- dst.internalComplete(t, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- // version of ThenCopy for CompletableFuture<Void> dst
- static final class ThenPropagate extends Completion {
- final CompletableFuture<?> src;
- final CompletableFuture<Void> dst;
- ThenPropagate(CompletableFuture<?> src,
- CompletableFuture<Void> dst) {
- this.src = src; this.dst = dst;
- }
- public final void run() {
- final CompletableFuture<?> a;
- final CompletableFuture<Void> dst;
- Object r; Throwable ex;
- if ((dst = this.dst) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult)
- ex = ((AltResult)r).ex;
- else
- ex = null;
- dst.internalComplete(null, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class HandleCompletion<T,U> extends Completion {
- final CompletableFuture<? extends T> src;
- final BiFunction<? super T, Throwable, ? extends U> fn;
- final CompletableFuture<U> dst;
- final Executor executor;
- HandleCompletion(CompletableFuture<? extends T> src,
- BiFunction<? super T, Throwable, ? extends U> fn,
- CompletableFuture<U> dst,
- Executor executor) {
- this.src = src; this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final BiFunction<? super T, Throwable, ? extends U> fn;
- final CompletableFuture<U> dst;
- Object r; T t; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- Executor e = executor;
- U u = null;
- Throwable dx = null;
- try {
- if (e != null)
- execAsync(e, new AsyncCombine<T,Throwable,U>(t, ex, fn, dst));
- else
- u = fn.apply(t, ex);
- } catch (Throwable rex) {
- dx = rex;
- }
- if (e == null || dx != null)
- dst.internalComplete(u, dx);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class ThenCompose<T,U> extends Completion {
- final CompletableFuture<? extends T> src;
- final Function<? super T, ? extends CompletionStage<U>> fn;
- final CompletableFuture<U> dst;
- final Executor executor;
- ThenCompose(CompletableFuture<? extends T> src,
- Function<? super T, ? extends CompletionStage<U>> fn,
- CompletableFuture<U> dst,
- Executor executor) {
- this.src = src; this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final Function<? super T, ? extends CompletionStage<U>> fn;
- final CompletableFuture<U> dst;
- Object r; T t; Throwable ex; Executor e;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- CompletableFuture<U> c = null;
- U u = null;
- boolean complete = false;
- if (ex == null) {
- if ((e = executor) != null)
- execAsync(e, new AsyncCompose<T,U>(t, fn, dst));
- else {
- try {
- CompletionStage<U> cs = fn.apply(t);
- c = (cs == null) ? null : cs.toCompletableFuture();
- if (c == null)
- ex = new NullPointerException();
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- }
- if (c != null) {
- ThenCopy<U> d = null;
- Object s;
- if ((s = c.result) == null) {
- CompletionNode p = new CompletionNode
- (d = new ThenCopy<U>(c, dst));
- while ((s = c.result) == null) {
- if (UNSAFE.compareAndSwapObject
- (c, COMPLETIONS, p.next = c.completions, p))
- break;
- }
- }
- if (s != null && (d == null || d.compareAndSet(0, 1))) {
- complete = true;
- if (s instanceof AltResult) {
- ex = ((AltResult)s).ex; // no rewrap
- u = null;
- }
- else {
- @SuppressWarnings("unchecked") U us = (U) s;
- u = us;
- }
- }
- }
- if (complete || ex != null)
- dst.internalComplete(u, ex);
- if (c != null)
- c.helpPostComplete();
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- // Implementations of stage methods with (plain, async, Executor) forms
-
- private <U> CompletableFuture<U> doThenApply
- (Function<? super T,? extends U> fn,
- Executor e) {
- if (fn == null) throw new NullPointerException();
- CompletableFuture<U> dst = new CompletableFuture<U>();
- ThenApply<T,U> d = null;
- Object r;
- if ((r = result) == null) {
- CompletionNode p = new CompletionNode
- (d = new ThenApply<T,U>(this, fn, dst, e));
- while ((r = result) == null) {
- if (UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p))
- break;
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- T t; Throwable ex;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- U u = null;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncApply<T,U>(t, fn, dst));
- else
- u = fn.apply(t);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(u, ex);
- }
- helpPostComplete();
- return dst;
- }
-
- private CompletableFuture<Void> doThenAccept(Consumer<? super T> fn,
- Executor e) {
- if (fn == null) throw new NullPointerException();
- CompletableFuture<Void> dst = new CompletableFuture<Void>();
- ThenAccept<T> d = null;
- Object r;
- if ((r = result) == null) {
- CompletionNode p = new CompletionNode
- (d = new ThenAccept<T>(this, fn, dst, e));
- while ((r = result) == null) {
- if (UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p))
- break;
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- T t; Throwable ex;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncAccept<T>(t, fn, dst));
- else
- fn.accept(t);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- helpPostComplete();
- return dst;
- }
-
- private CompletableFuture<Void> doThenRun(Runnable action,
- Executor e) {
- if (action == null) throw new NullPointerException();
- CompletableFuture<Void> dst = new CompletableFuture<Void>();
- ThenRun d = null;
- Object r;
- if ((r = result) == null) {
- CompletionNode p = new CompletionNode
- (d = new ThenRun(this, action, dst, e));
- while ((r = result) == null) {
- if (UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p))
- break;
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- Throwable ex;
- if (r instanceof AltResult)
- ex = ((AltResult)r).ex;
- else
- ex = null;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncRun(action, dst));
- else
- action.run();
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- helpPostComplete();
- return dst;
- }
-
- private <U,V> CompletableFuture<V> doThenCombine
- (CompletableFuture<? extends U> other,
- BiFunction<? super T,? super U,? extends V> fn,
- Executor e) {
- if (other == null || fn == null) throw new NullPointerException();
- CompletableFuture<V> dst = new CompletableFuture<V>();
- ThenCombine<T,U,V> d = null;
- Object r, s = null;
- if ((r = result) == null || (s = other.result) == null) {
- d = new ThenCombine<T,U,V>(this, other, fn, dst, e);
- CompletionNode q = null, p = new CompletionNode(d);
- while ((r == null && (r = result) == null) ||
- (s == null && (s = other.result) == null)) {
- if (q != null) {
- if (s != null ||
- UNSAFE.compareAndSwapObject
- (other, COMPLETIONS, q.next = other.completions, q))
- break;
- }
- else if (r != null ||
- UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p)) {
- if (s != null)
- break;
- q = new CompletionNode(d);
+ ForkJoinPool.managedBlock(q);
+ } catch (InterruptedException ie) {
+ q.interruptControl = -1;
}
}
}
- if (r != null && s != null && (d == null || d.compareAndSet(0, 1))) {
- T t; U u; Throwable ex;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- if (ex != null)
- u = null;
- else if (s instanceof AltResult) {
- ex = ((AltResult)s).ex;
- u = null;
- }
- else {
- @SuppressWarnings("unchecked") U us = (U) s;
- u = us;
- }
- V v = null;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncCombine<T,U,V>(t, u, fn, dst));
- else
- v = fn.apply(t, u);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(v, ex);
- }
- helpPostComplete();
- other.helpPostComplete();
- return dst;
- }
-
- private <U> CompletableFuture<Void> doThenAcceptBoth
- (CompletableFuture<? extends U> other,
- BiConsumer<? super T,? super U> fn,
- Executor e) {
- if (other == null || fn == null) throw new NullPointerException();
- CompletableFuture<Void> dst = new CompletableFuture<Void>();
- ThenAcceptBoth<T,U> d = null;
- Object r, s = null;
- if ((r = result) == null || (s = other.result) == null) {
- d = new ThenAcceptBoth<T,U>(this, other, fn, dst, e);
- CompletionNode q = null, p = new CompletionNode(d);
- while ((r == null && (r = result) == null) ||
- (s == null && (s = other.result) == null)) {
- if (q != null) {
- if (s != null ||
- UNSAFE.compareAndSwapObject
- (other, COMPLETIONS, q.next = other.completions, q))
- break;
- }
- else if (r != null ||
- UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p)) {
- if (s != null)
- break;
- q = new CompletionNode(d);
- }
- }
- }
- if (r != null && s != null && (d == null || d.compareAndSet(0, 1))) {
- T t; U u; Throwable ex;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- if (ex != null)
- u = null;
- else if (s instanceof AltResult) {
- ex = ((AltResult)s).ex;
- u = null;
- }
- else {
- @SuppressWarnings("unchecked") U us = (U) s;
- u = us;
- }
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncAcceptBoth<T,U>(t, u, fn, dst));
- else
- fn.accept(t, u);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- helpPostComplete();
- other.helpPostComplete();
- return dst;
- }
-
- private CompletableFuture<Void> doRunAfterBoth(CompletableFuture<?> other,
- Runnable action,
- Executor e) {
- if (other == null || action == null) throw new NullPointerException();
- CompletableFuture<Void> dst = new CompletableFuture<Void>();
- RunAfterBoth d = null;
- Object r, s = null;
- if ((r = result) == null || (s = other.result) == null) {
- d = new RunAfterBoth(this, other, action, dst, e);
- CompletionNode q = null, p = new CompletionNode(d);
- while ((r == null && (r = result) == null) ||
- (s == null && (s = other.result) == null)) {
- if (q != null) {
- if (s != null ||
- UNSAFE.compareAndSwapObject
- (other, COMPLETIONS, q.next = other.completions, q))
- break;
- }
- else if (r != null ||
- UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p)) {
- if (s != null)
- break;
- q = new CompletionNode(d);
- }
- }
- }
- if (r != null && s != null && (d == null || d.compareAndSet(0, 1))) {
- Throwable ex;
- if (r instanceof AltResult)
- ex = ((AltResult)r).ex;
- else
- ex = null;
- if (ex == null && (s instanceof AltResult))
- ex = ((AltResult)s).ex;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncRun(action, dst));
- else
- action.run();
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- helpPostComplete();
- other.helpPostComplete();
- return dst;
- }
-
- private <U> CompletableFuture<U> doApplyToEither
- (CompletableFuture<? extends T> other,
- Function<? super T, U> fn,
- Executor e) {
- if (other == null || fn == null) throw new NullPointerException();
- CompletableFuture<U> dst = new CompletableFuture<U>();
- ApplyToEither<T,U> d = null;
- Object r;
- if ((r = result) == null && (r = other.result) == null) {
- d = new ApplyToEither<T,U>(this, other, fn, dst, e);
- CompletionNode q = null, p = new CompletionNode(d);
- while ((r = result) == null && (r = other.result) == null) {
- if (q != null) {
- if (UNSAFE.compareAndSwapObject
- (other, COMPLETIONS, q.next = other.completions, q))
- break;
- }
- else if (UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p))
- q = new CompletionNode(d);
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- T t; Throwable ex;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- U u = null;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncApply<T,U>(t, fn, dst));
- else
- u = fn.apply(t);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(u, ex);
- }
- helpPostComplete();
- other.helpPostComplete();
- return dst;
+ if (q.interruptControl < 0)
+ r = null;
+ q.thread = null;
+ postComplete();
+ return r;
}
- private CompletableFuture<Void> doAcceptEither
- (CompletableFuture<? extends T> other,
- Consumer<? super T> fn,
- Executor e) {
- if (other == null || fn == null) throw new NullPointerException();
- CompletableFuture<Void> dst = new CompletableFuture<Void>();
- AcceptEither<T> d = null;
- Object r;
- if ((r = result) == null && (r = other.result) == null) {
- d = new AcceptEither<T>(this, other, fn, dst, e);
- CompletionNode q = null, p = new CompletionNode(d);
- while ((r = result) == null && (r = other.result) == null) {
- if (q != null) {
- if (UNSAFE.compareAndSwapObject
- (other, COMPLETIONS, q.next = other.completions, q))
- break;
- }
- else if (UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p))
- q = new CompletionNode(d);
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- T t; Throwable ex;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncAccept<T>(t, fn, dst));
- else
- fn.accept(t);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- helpPostComplete();
- other.helpPostComplete();
- return dst;
- }
-
- private CompletableFuture<Void> doRunAfterEither
- (CompletableFuture<?> other,
- Runnable action,
- Executor e) {
- if (other == null || action == null) throw new NullPointerException();
- CompletableFuture<Void> dst = new CompletableFuture<Void>();
- RunAfterEither d = null;
- Object r;
- if ((r = result) == null && (r = other.result) == null) {
- d = new RunAfterEither(this, other, action, dst, e);
- CompletionNode q = null, p = new CompletionNode(d);
- while ((r = result) == null && (r = other.result) == null) {
- if (q != null) {
- if (UNSAFE.compareAndSwapObject
- (other, COMPLETIONS, q.next = other.completions, q))
- break;
- }
- else if (UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p))
- q = new CompletionNode(d);
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- Throwable ex;
- if (r instanceof AltResult)
- ex = ((AltResult)r).ex;
- else
- ex = null;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncRun(action, dst));
- else
- action.run();
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- helpPostComplete();
- other.helpPostComplete();
- return dst;
- }
-
- private <U> CompletableFuture<U> doThenCompose
- (Function<? super T, ? extends CompletionStage<U>> fn,
- Executor e) {
- if (fn == null) throw new NullPointerException();
- CompletableFuture<U> dst = null;
- ThenCompose<T,U> d = null;
- Object r;
- if ((r = result) == null) {
- dst = new CompletableFuture<U>();
- CompletionNode p = new CompletionNode
- (d = new ThenCompose<T,U>(this, fn, dst, e));
- while ((r = result) == null) {
- if (UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p))
- break;
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- T t; Throwable ex;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- if (ex == null) {
- if (e != null) {
- if (dst == null)
- dst = new CompletableFuture<U>();
- execAsync(e, new AsyncCompose<T,U>(t, fn, dst));
- }
- else {
- try {
- CompletionStage<U> cs = fn.apply(t);
- if (cs == null ||
- (dst = cs.toCompletableFuture()) == null)
- ex = new NullPointerException();
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- }
- if (dst == null)
- dst = new CompletableFuture<U>();
- if (ex != null)
- dst.internalComplete(null, ex);
- }
- helpPostComplete();
- dst.helpPostComplete();
- return dst;
- }
-
- private CompletableFuture<T> doWhenComplete
- (BiConsumer<? super T, ? super Throwable> fn,
- Executor e) {
- if (fn == null) throw new NullPointerException();
- CompletableFuture<T> dst = new CompletableFuture<T>();
- WhenCompleteCompletion<T> d = null;
- Object r;
- if ((r = result) == null) {
- CompletionNode p =
- new CompletionNode(d = new WhenCompleteCompletion<T>
- (this, fn, dst, e));
- while ((r = result) == null) {
- if (UNSAFE.compareAndSwapObject(this, COMPLETIONS,
- p.next = completions, p))
- break;
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- T t; Throwable ex;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- Throwable dx = null;
- try {
- if (e != null)
- execAsync(e, new AsyncWhenComplete<T>(t, ex, fn, dst));
- else
- fn.accept(t, ex);
- } catch (Throwable rex) {
- dx = rex;
- }
- if (e == null || dx != null)
- dst.internalComplete(t, ex != null ? ex : dx);
- }
- helpPostComplete();
- return dst;
- }
-
- private <U> CompletableFuture<U> doHandle
- (BiFunction<? super T, Throwable, ? extends U> fn,
- Executor e) {
- if (fn == null) throw new NullPointerException();
- CompletableFuture<U> dst = new CompletableFuture<U>();
- HandleCompletion<T,U> d = null;
- Object r;
- if ((r = result) == null) {
- CompletionNode p =
- new CompletionNode(d = new HandleCompletion<T,U>
- (this, fn, dst, e));
- while ((r = result) == null) {
- if (UNSAFE.compareAndSwapObject(this, COMPLETIONS,
- p.next = completions, p))
- break;
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- T t; Throwable ex;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- U u = null;
- Throwable dx = null;
- try {
- if (e != null)
- execAsync(e, new AsyncCombine<T,Throwable,U>(t, ex, fn, dst));
- else {
- u = fn.apply(t, ex);
- dx = null;
- }
- } catch (Throwable rex) {
- dx = rex;
- u = null;
- }
- if (e == null || dx != null)
- dst.internalComplete(u, dx);
- }
- helpPostComplete();
- return dst;
- }
-
-
- // public methods
+ /* ------------- public methods -------------- */
/**
* Creates a new incomplete CompletableFuture.
@@ -2114,6 +1786,13 @@
}
/**
+ * Creates a new complete CompletableFuture with given encoded result.
+ */
+ private CompletableFuture(Object r) {
+ this.result = r;
+ }
+
+ /**
* Returns a new CompletableFuture that is asynchronously completed
* by a task running in the {@link ForkJoinPool#commonPool()} with
* the value obtained by calling the given Supplier.
@@ -2124,10 +1803,7 @@
* @return the new CompletableFuture
*/
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
- if (supplier == null) throw new NullPointerException();
- CompletableFuture<U> f = new CompletableFuture<U>();
- execAsync(ForkJoinPool.commonPool(), new AsyncSupply<U>(supplier, f));
- return f;
+ return asyncSupplyStage(asyncPool, supplier);
}
/**
@@ -2143,11 +1819,7 @@
*/
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
Executor executor) {
- if (executor == null || supplier == null)
- throw new NullPointerException();
- CompletableFuture<U> f = new CompletableFuture<U>();
- execAsync(executor, new AsyncSupply<U>(supplier, f));
- return f;
+ return asyncSupplyStage(screenExecutor(executor), supplier);
}
/**
@@ -2160,10 +1832,7 @@
* @return the new CompletableFuture
*/
public static CompletableFuture<Void> runAsync(Runnable runnable) {
- if (runnable == null) throw new NullPointerException();
- CompletableFuture<Void> f = new CompletableFuture<Void>();
- execAsync(ForkJoinPool.commonPool(), new AsyncRun(runnable, f));
- return f;
+ return asyncRunStage(asyncPool, runnable);
}
/**
@@ -2178,11 +1847,7 @@
*/
public static CompletableFuture<Void> runAsync(Runnable runnable,
Executor executor) {
- if (executor == null || runnable == null)
- throw new NullPointerException();
- CompletableFuture<Void> f = new CompletableFuture<Void>();
- execAsync(executor, new AsyncRun(runnable, f));
- return f;
+ return asyncRunStage(screenExecutor(executor), runnable);
}
/**
@@ -2194,9 +1859,7 @@
* @return the completed CompletableFuture
*/
public static <U> CompletableFuture<U> completedFuture(U value) {
- CompletableFuture<U> f = new CompletableFuture<U>();
- f.result = (value == null) ? NIL : value;
- return f;
+ return new CompletableFuture<U>((value == null) ? NIL : value);
}
/**
@@ -2220,21 +1883,8 @@
* while waiting
*/
public T get() throws InterruptedException, ExecutionException {
- Object r; Throwable ex, cause;
- if ((r = result) == null && (r = waitingGet(true)) == null)
- throw new InterruptedException();
- if (!(r instanceof AltResult)) {
- @SuppressWarnings("unchecked") T tr = (T) r;
- return tr;
- }
- if ((ex = ((AltResult)r).ex) == null)
- return null;
- if (ex instanceof CancellationException)
- throw (CancellationException)ex;
- if ((ex instanceof CompletionException) &&
- (cause = ex.getCause()) != null)
- ex = cause;
- throw new ExecutionException(ex);
+ Object r;
+ return reportGet((r = result) == null ? waitingGet(true) : r);
}
/**
@@ -2252,24 +1902,9 @@
*/
public T get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
- Object r; Throwable ex, cause;
+ Object r;
long nanos = unit.toNanos(timeout);
- if (Thread.interrupted())
- throw new InterruptedException();
- if ((r = result) == null)
- r = timedAwaitDone(nanos);
- if (!(r instanceof AltResult)) {
- @SuppressWarnings("unchecked") T tr = (T) r;
- return tr;
- }
- if ((ex = ((AltResult)r).ex) == null)
- return null;
- if (ex instanceof CancellationException)
- throw (CancellationException)ex;
- if ((ex instanceof CompletionException) &&
- (cause = ex.getCause()) != null)
- ex = cause;
- throw new ExecutionException(ex);
+ return reportGet((r = result) == null ? timedGet(nanos) : r);
}
/**
@@ -2287,20 +1922,8 @@
* exceptionally or a completion computation threw an exception
*/
public T join() {
- Object r; Throwable ex;
- if ((r = result) == null)
- r = waitingGet(false);
- if (!(r instanceof AltResult)) {
- @SuppressWarnings("unchecked") T tr = (T) r;
- return tr;
- }
- if ((ex = ((AltResult)r).ex) == null)
- return null;
- if (ex instanceof CancellationException)
- throw (CancellationException)ex;
- if (ex instanceof CompletionException)
- throw (CompletionException)ex;
- throw new CompletionException(ex);
+ Object r;
+ return reportJoin((r = result) == null ? waitingGet(false) : r);
}
/**
@@ -2314,20 +1937,8 @@
* exceptionally or a completion computation threw an exception
*/
public T getNow(T valueIfAbsent) {
- Object r; Throwable ex;
- if ((r = result) == null)
- return valueIfAbsent;
- if (!(r instanceof AltResult)) {
- @SuppressWarnings("unchecked") T tr = (T) r;
- return tr;
- }
- if ((ex = ((AltResult)r).ex) == null)
- return null;
- if (ex instanceof CancellationException)
- throw (CancellationException)ex;
- if (ex instanceof CompletionException)
- throw (CompletionException)ex;
- throw new CompletionException(ex);
+ Object r;
+ return ((r = result) == null) ? valueIfAbsent : reportJoin(r);
}
/**
@@ -2339,9 +1950,7 @@
* to transition to a completed state, else {@code false}
*/
public boolean complete(T value) {
- boolean triggered = result == null &&
- UNSAFE.compareAndSwapObject(this, RESULT, null,
- value == null ? NIL : value);
+ boolean triggered = completeValue(value);
postComplete();
return triggered;
}
@@ -2356,244 +1965,200 @@
*/
public boolean completeExceptionally(Throwable ex) {
if (ex == null) throw new NullPointerException();
- boolean triggered = result == null &&
- UNSAFE.compareAndSwapObject(this, RESULT, null, new AltResult(ex));
+ boolean triggered = internalComplete(new AltResult(ex));
postComplete();
return triggered;
}
- // CompletionStage methods
-
- public <U> CompletableFuture<U> thenApply
- (Function<? super T,? extends U> fn) {
- return doThenApply(fn, null);
+ public <U> CompletableFuture<U> thenApply(
+ Function<? super T,? extends U> fn) {
+ return uniApplyStage(null, fn);
}
- public <U> CompletableFuture<U> thenApplyAsync
- (Function<? super T,? extends U> fn) {
- return doThenApply(fn, ForkJoinPool.commonPool());
+ public <U> CompletableFuture<U> thenApplyAsync(
+ Function<? super T,? extends U> fn) {
+ return uniApplyStage(asyncPool, fn);
}
- public <U> CompletableFuture<U> thenApplyAsync
- (Function<? super T,? extends U> fn,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doThenApply(fn, executor);
+ public <U> CompletableFuture<U> thenApplyAsync(
+ Function<? super T,? extends U> fn, Executor executor) {
+ return uniApplyStage(screenExecutor(executor), fn);
}
- public CompletableFuture<Void> thenAccept
- (Consumer<? super T> action) {
- return doThenAccept(action, null);
+ public CompletableFuture<Void> thenAccept(Consumer<? super T> action) {
+ return uniAcceptStage(null, action);
}
- public CompletableFuture<Void> thenAcceptAsync
- (Consumer<? super T> action) {
- return doThenAccept(action, ForkJoinPool.commonPool());
+ public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) {
+ return uniAcceptStage(asyncPool, action);
}
- public CompletableFuture<Void> thenAcceptAsync
- (Consumer<? super T> action,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doThenAccept(action, executor);
+ public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,
+ Executor executor) {
+ return uniAcceptStage(screenExecutor(executor), action);
}
- public CompletableFuture<Void> thenRun
- (Runnable action) {
- return doThenRun(action, null);
+ public CompletableFuture<Void> thenRun(Runnable action) {
+ return uniRunStage(null, action);
}
- public CompletableFuture<Void> thenRunAsync
- (Runnable action) {
- return doThenRun(action, ForkJoinPool.commonPool());
+ public CompletableFuture<Void> thenRunAsync(Runnable action) {
+ return uniRunStage(asyncPool, action);
}
- public CompletableFuture<Void> thenRunAsync
- (Runnable action,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doThenRun(action, executor);
+ public CompletableFuture<Void> thenRunAsync(Runnable action,
+ Executor executor) {
+ return uniRunStage(screenExecutor(executor), action);
}
- public <U,V> CompletableFuture<V> thenCombine
- (CompletionStage<? extends U> other,
- BiFunction<? super T,? super U,? extends V> fn) {
- return doThenCombine(other.toCompletableFuture(), fn, null);
+ public <U,V> CompletableFuture<V> thenCombine(
+ CompletionStage<? extends U> other,
+ BiFunction<? super T,? super U,? extends V> fn) {
+ return biApplyStage(null, other, fn);
}
- public <U,V> CompletableFuture<V> thenCombineAsync
- (CompletionStage<? extends U> other,
- BiFunction<? super T,? super U,? extends V> fn) {
- return doThenCombine(other.toCompletableFuture(), fn,
- ForkJoinPool.commonPool());
+ public <U,V> CompletableFuture<V> thenCombineAsync(
+ CompletionStage<? extends U> other,
+ BiFunction<? super T,? super U,? extends V> fn) {
+ return biApplyStage(asyncPool, other, fn);
}
- public <U,V> CompletableFuture<V> thenCombineAsync
- (CompletionStage<? extends U> other,
- BiFunction<? super T,? super U,? extends V> fn,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doThenCombine(other.toCompletableFuture(), fn, executor);
+ public <U,V> CompletableFuture<V> thenCombineAsync(
+ CompletionStage<? extends U> other,
+ BiFunction<? super T,? super U,? extends V> fn, Executor executor) {
+ return biApplyStage(screenExecutor(executor), other, fn);
}
- public <U> CompletableFuture<Void> thenAcceptBoth
- (CompletionStage<? extends U> other,
- BiConsumer<? super T, ? super U> action) {
- return doThenAcceptBoth(other.toCompletableFuture(), action, null);
+ public <U> CompletableFuture<Void> thenAcceptBoth(
+ CompletionStage<? extends U> other,
+ BiConsumer<? super T, ? super U> action) {
+ return biAcceptStage(null, other, action);
}
- public <U> CompletableFuture<Void> thenAcceptBothAsync
- (CompletionStage<? extends U> other,
- BiConsumer<? super T, ? super U> action) {
- return doThenAcceptBoth(other.toCompletableFuture(), action,
- ForkJoinPool.commonPool());
+ public <U> CompletableFuture<Void> thenAcceptBothAsync(
+ CompletionStage<? extends U> other,
+ BiConsumer<? super T, ? super U> action) {
+ return biAcceptStage(asyncPool, other, action);
}
- public <U> CompletableFuture<Void> thenAcceptBothAsync
- (CompletionStage<? extends U> other,
- BiConsumer<? super T, ? super U> action,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doThenAcceptBoth(other.toCompletableFuture(), action, executor);
- }
-
- public CompletableFuture<Void> runAfterBoth
- (CompletionStage<?> other,
- Runnable action) {
- return doRunAfterBoth(other.toCompletableFuture(), action, null);
+ public <U> CompletableFuture<Void> thenAcceptBothAsync(
+ CompletionStage<? extends U> other,
+ BiConsumer<? super T, ? super U> action, Executor executor) {
+ return biAcceptStage(screenExecutor(executor), other, action);
}
- public CompletableFuture<Void> runAfterBothAsync
- (CompletionStage<?> other,
- Runnable action) {
- return doRunAfterBoth(other.toCompletableFuture(), action,
- ForkJoinPool.commonPool());
+ public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,
+ Runnable action) {
+ return biRunStage(null, other, action);
}
- public CompletableFuture<Void> runAfterBothAsync
- (CompletionStage<?> other,
- Runnable action,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doRunAfterBoth(other.toCompletableFuture(), action, executor);
+ public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
+ Runnable action) {
+ return biRunStage(asyncPool, other, action);
}
-
- public <U> CompletableFuture<U> applyToEither
- (CompletionStage<? extends T> other,
- Function<? super T, U> fn) {
- return doApplyToEither(other.toCompletableFuture(), fn, null);
+ public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
+ Runnable action,
+ Executor executor) {
+ return biRunStage(screenExecutor(executor), other, action);
}
- public <U> CompletableFuture<U> applyToEitherAsync
- (CompletionStage<? extends T> other,
- Function<? super T, U> fn) {
- return doApplyToEither(other.toCompletableFuture(), fn,
- ForkJoinPool.commonPool());
+ public <U> CompletableFuture<U> applyToEither(
+ CompletionStage<? extends T> other, Function<? super T, U> fn) {
+ return orApplyStage(null, other, fn);
+ }
+
+ public <U> CompletableFuture<U> applyToEitherAsync(
+ CompletionStage<? extends T> other, Function<? super T, U> fn) {
+ return orApplyStage(asyncPool, other, fn);
}
- public <U> CompletableFuture<U> applyToEitherAsync
- (CompletionStage<? extends T> other,
- Function<? super T, U> fn,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doApplyToEither(other.toCompletableFuture(), fn, executor);
- }
-
- public CompletableFuture<Void> acceptEither
- (CompletionStage<? extends T> other,
- Consumer<? super T> action) {
- return doAcceptEither(other.toCompletableFuture(), action, null);
+ public <U> CompletableFuture<U> applyToEitherAsync(
+ CompletionStage<? extends T> other, Function<? super T, U> fn,
+ Executor executor) {
+ return orApplyStage(screenExecutor(executor), other, fn);
}
- public CompletableFuture<Void> acceptEitherAsync
- (CompletionStage<? extends T> other,
- Consumer<? super T> action) {
- return doAcceptEither(other.toCompletableFuture(), action,
- ForkJoinPool.commonPool());
+ public CompletableFuture<Void> acceptEither(
+ CompletionStage<? extends T> other, Consumer<? super T> action) {
+ return orAcceptStage(null, other, action);
}
- public CompletableFuture<Void> acceptEitherAsync
- (CompletionStage<? extends T> other,
- Consumer<? super T> action,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doAcceptEither(other.toCompletableFuture(), action, executor);
+ public CompletableFuture<Void> acceptEitherAsync(
+ CompletionStage<? extends T> other, Consumer<? super T> action) {
+ return orAcceptStage(asyncPool, other, action);
+ }
+
+ public CompletableFuture<Void> acceptEitherAsync(
+ CompletionStage<? extends T> other, Consumer<? super T> action,
+ Executor executor) {
+ return orAcceptStage(screenExecutor(executor), other, action);
}
public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,
Runnable action) {
- return doRunAfterEither(other.toCompletableFuture(), action, null);
+ return orRunStage(null, other, action);
}
- public CompletableFuture<Void> runAfterEitherAsync
- (CompletionStage<?> other,
- Runnable action) {
- return doRunAfterEither(other.toCompletableFuture(), action,
- ForkJoinPool.commonPool());
+ public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
+ Runnable action) {
+ return orRunStage(asyncPool, other, action);
}
- public CompletableFuture<Void> runAfterEitherAsync
- (CompletionStage<?> other,
- Runnable action,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doRunAfterEither(other.toCompletableFuture(), action, executor);
+ public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
+ Runnable action,
+ Executor executor) {
+ return orRunStage(screenExecutor(executor), other, action);
}
- public <U> CompletableFuture<U> thenCompose
- (Function<? super T, ? extends CompletionStage<U>> fn) {
- return doThenCompose(fn, null);
+ public <U> CompletableFuture<U> thenCompose(
+ Function<? super T, ? extends CompletionStage<U>> fn) {
+ return uniComposeStage(null, fn);
}
- public <U> CompletableFuture<U> thenComposeAsync
- (Function<? super T, ? extends CompletionStage<U>> fn) {
- return doThenCompose(fn, ForkJoinPool.commonPool());
+ public <U> CompletableFuture<U> thenComposeAsync(
+ Function<? super T, ? extends CompletionStage<U>> fn) {
+ return uniComposeStage(asyncPool, fn);
}
- public <U> CompletableFuture<U> thenComposeAsync
- (Function<? super T, ? extends CompletionStage<U>> fn,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doThenCompose(fn, executor);
+ public <U> CompletableFuture<U> thenComposeAsync(
+ Function<? super T, ? extends CompletionStage<U>> fn,
+ Executor executor) {
+ return uniComposeStage(screenExecutor(executor), fn);
}
- public CompletableFuture<T> whenComplete
- (BiConsumer<? super T, ? super Throwable> action) {
- return doWhenComplete(action, null);
+ public CompletableFuture<T> whenComplete(
+ BiConsumer<? super T, ? super Throwable> action) {
+ return uniWhenCompleteStage(null, action);
}
- public CompletableFuture<T> whenCompleteAsync
- (BiConsumer<? super T, ? super Throwable> action) {
- return doWhenComplete(action, ForkJoinPool.commonPool());
+ public CompletableFuture<T> whenCompleteAsync(
+ BiConsumer<? super T, ? super Throwable> action) {
+ return uniWhenCompleteStage(asyncPool, action);
}
- public CompletableFuture<T> whenCompleteAsync
- (BiConsumer<? super T, ? super Throwable> action,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doWhenComplete(action, executor);
+ public CompletableFuture<T> whenCompleteAsync(
+ BiConsumer<? super T, ? super Throwable> action, Executor executor) {
+ return uniWhenCompleteStage(screenExecutor(executor), action);
}
- public <U> CompletableFuture<U> handle
- (BiFunction<? super T, Throwable, ? extends U> fn) {
- return doHandle(fn, null);
+ public <U> CompletableFuture<U> handle(
+ BiFunction<? super T, Throwable, ? extends U> fn) {
+ return uniHandleStage(null, fn);
}
- public <U> CompletableFuture<U> handleAsync
- (BiFunction<? super T, Throwable, ? extends U> fn) {
- return doHandle(fn, ForkJoinPool.commonPool());
+ public <U> CompletableFuture<U> handleAsync(
+ BiFunction<? super T, Throwable, ? extends U> fn) {
+ return uniHandleStage(asyncPool, fn);
}
- public <U> CompletableFuture<U> handleAsync
- (BiFunction<? super T, Throwable, ? extends U> fn,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doHandle(fn, executor);
+ public <U> CompletableFuture<U> handleAsync(
+ BiFunction<? super T, Throwable, ? extends U> fn, Executor executor) {
+ return uniHandleStage(screenExecutor(executor), fn);
}
/**
- * Returns this CompletableFuture
+ * Returns this CompletableFuture.
*
* @return this CompletableFuture
*/
@@ -2618,52 +2183,13 @@
* exceptionally
* @return the new CompletableFuture
*/
- public CompletableFuture<T> exceptionally
- (Function<Throwable, ? extends T> fn) {
- if (fn == null) throw new NullPointerException();
- CompletableFuture<T> dst = new CompletableFuture<T>();
- ExceptionCompletion<T> d = null;
- Object r;
- if ((r = result) == null) {
- CompletionNode p =
- new CompletionNode(d = new ExceptionCompletion<T>
- (this, fn, dst));
- while ((r = result) == null) {
- if (UNSAFE.compareAndSwapObject(this, COMPLETIONS,
- p.next = completions, p))
- break;
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- T t = null; Throwable ex, dx = null;
- if (r instanceof AltResult) {
- if ((ex = ((AltResult)r).ex) != null) {
- try {
- t = fn.apply(ex);
- } catch (Throwable rex) {
- dx = rex;
- }
- }
- }
- else {
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- dst.internalComplete(t, dx);
- }
- helpPostComplete();
- return dst;
+ public CompletableFuture<T> exceptionally(
+ Function<Throwable, ? extends T> fn) {
+ return uniExceptionallyStage(fn);
}
/* ------------- Arbitrary-arity constructions -------------- */
- /*
- * The basic plan of attack is to recursively form binary
- * completion trees of elements. This can be overkill for small
- * sets, but scales nicely. The And/All vs Or/Any forms use the
- * same idea, but details differ.
- */
-
/**
* Returns a new CompletableFuture that is completed when all of
* the given CompletableFutures complete. If any of the given
@@ -2688,82 +2214,7 @@
* {@code null}
*/
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
- int len = cfs.length; // Directly handle empty and singleton cases
- if (len > 1)
- return allTree(cfs, 0, len - 1);
- else {
- CompletableFuture<Void> dst = new CompletableFuture<Void>();
- CompletableFuture<?> f;
- if (len == 0)
- dst.result = NIL;
- else if ((f = cfs[0]) == null)
- throw new NullPointerException();
- else {
- ThenPropagate d = null;
- CompletionNode p = null;
- Object r;
- while ((r = f.result) == null) {
- if (d == null)
- d = new ThenPropagate(f, dst);
- else if (p == null)
- p = new CompletionNode(d);
- else if (UNSAFE.compareAndSwapObject
- (f, COMPLETIONS, p.next = f.completions, p))
- break;
- }
- if (r != null && (d == null || d.compareAndSet(0, 1)))
- dst.internalComplete(null, (r instanceof AltResult) ?
- ((AltResult)r).ex : null);
- f.helpPostComplete();
- }
- return dst;
- }
- }
-
- /**
- * Recursively constructs an And'ed tree of CompletableFutures.
- * Called only when array known to have at least two elements.
- */
- private static CompletableFuture<Void> allTree(CompletableFuture<?>[] cfs,
- int lo, int hi) {
- CompletableFuture<?> fst, snd;
- int mid = (lo + hi) >>> 1;
- if ((fst = (lo == mid ? cfs[lo] : allTree(cfs, lo, mid))) == null ||
- (snd = (hi == mid+1 ? cfs[hi] : allTree(cfs, mid+1, hi))) == null)
- throw new NullPointerException();
- CompletableFuture<Void> dst = new CompletableFuture<Void>();
- AndCompletion d = null;
- CompletionNode p = null, q = null;
- Object r = null, s = null;
- while ((r = fst.result) == null || (s = snd.result) == null) {
- if (d == null)
- d = new AndCompletion(fst, snd, dst);
- else if (p == null)
- p = new CompletionNode(d);
- else if (q == null) {
- if (UNSAFE.compareAndSwapObject
- (fst, COMPLETIONS, p.next = fst.completions, p))
- q = new CompletionNode(d);
- }
- else if (UNSAFE.compareAndSwapObject
- (snd, COMPLETIONS, q.next = snd.completions, q))
- break;
- }
- if ((r != null || (r = fst.result) != null) &&
- (s != null || (s = snd.result) != null) &&
- (d == null || d.compareAndSet(0, 1))) {
- Throwable ex;
- if (r instanceof AltResult)
- ex = ((AltResult)r).ex;
- else
- ex = null;
- if (ex == null && (s instanceof AltResult))
- ex = ((AltResult)s).ex;
- dst.internalComplete(null, ex);
- }
- fst.helpPostComplete();
- snd.helpPostComplete();
- return dst;
+ return andTree(cfs, 0, cfs.length - 1);
}
/**
@@ -2782,92 +2233,7 @@
* {@code null}
*/
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
- int len = cfs.length; // Same idea as allOf
- if (len > 1)
- return anyTree(cfs, 0, len - 1);
- else {
- CompletableFuture<Object> dst = new CompletableFuture<Object>();
- CompletableFuture<?> f;
- if (len == 0)
- ; // skip
- else if ((f = cfs[0]) == null)
- throw new NullPointerException();
- else {
- ThenCopy<Object> d = null;
- CompletionNode p = null;
- Object r;
- while ((r = f.result) == null) {
- if (d == null)
- d = new ThenCopy<Object>(f, dst);
- else if (p == null)
- p = new CompletionNode(d);
- else if (UNSAFE.compareAndSwapObject
- (f, COMPLETIONS, p.next = f.completions, p))
- break;
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- Throwable ex; Object t;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- t = r;
- }
- dst.internalComplete(t, ex);
- }
- f.helpPostComplete();
- }
- return dst;
- }
- }
-
- /**
- * Recursively constructs an Or'ed tree of CompletableFutures.
- */
- private static CompletableFuture<Object> anyTree(CompletableFuture<?>[] cfs,
- int lo, int hi) {
- CompletableFuture<?> fst, snd;
- int mid = (lo + hi) >>> 1;
- if ((fst = (lo == mid ? cfs[lo] : anyTree(cfs, lo, mid))) == null ||
- (snd = (hi == mid+1 ? cfs[hi] : anyTree(cfs, mid+1, hi))) == null)
- throw new NullPointerException();
- CompletableFuture<Object> dst = new CompletableFuture<Object>();
- OrCompletion d = null;
- CompletionNode p = null, q = null;
- Object r;
- while ((r = fst.result) == null && (r = snd.result) == null) {
- if (d == null)
- d = new OrCompletion(fst, snd, dst);
- else if (p == null)
- p = new CompletionNode(d);
- else if (q == null) {
- if (UNSAFE.compareAndSwapObject
- (fst, COMPLETIONS, p.next = fst.completions, p))
- q = new CompletionNode(d);
- }
- else if (UNSAFE.compareAndSwapObject
- (snd, COMPLETIONS, q.next = snd.completions, q))
- break;
- }
- if ((r != null || (r = fst.result) != null ||
- (r = snd.result) != null) &&
- (d == null || d.compareAndSet(0, 1))) {
- Throwable ex; Object t;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- t = r;
- }
- dst.internalComplete(t, ex);
- }
- fst.helpPostComplete();
- snd.helpPostComplete();
- return dst;
+ return orTree(cfs, 0, cfs.length - 1);
}
/* ------------- Control and status methods -------------- */
@@ -2887,8 +2253,7 @@
*/
public boolean cancel(boolean mayInterruptIfRunning) {
boolean cancelled = (result == null) &&
- UNSAFE.compareAndSwapObject
- (this, RESULT, null, new AltResult(new CancellationException()));
+ internalComplete(new AltResult(new CancellationException()));
postComplete();
return cancelled || isCancelled();
}
@@ -2940,11 +2305,12 @@
* Forcibly causes subsequent invocations of method {@link #get()}
* and related methods to throw the given exception, whether or
* not already completed. This method is designed for use only in
- * recovery actions, and even in such situations may result in
- * ongoing dependent completions using established versus
+ * error recovery actions, and even in such situations may result
+ * in ongoing dependent completions using established versus
* overwritten outcomes.
*
* @param ex the exception
+ * @throws NullPointerException if the exception is null
*/
public void obtrudeException(Throwable ex) {
if (ex == null) throw new NullPointerException();
@@ -2962,7 +2328,7 @@
*/
public int getNumberOfDependents() {
int count = 0;
- for (CompletionNode p = completions; p != null; p = p.next)
+ for (Completion p = stack; p != null; p = p.next)
++count;
return count;
}
@@ -2993,20 +2359,19 @@
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE;
private static final long RESULT;
- private static final long WAITERS;
- private static final long COMPLETIONS;
+ private static final long STACK;
+ private static final long NEXT;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
+ final sun.misc.Unsafe u;
+ UNSAFE = u = sun.misc.Unsafe.getUnsafe();
Class<?> k = CompletableFuture.class;
- RESULT = UNSAFE.objectFieldOffset
- (k.getDeclaredField("result"));
- WAITERS = UNSAFE.objectFieldOffset
- (k.getDeclaredField("waiters"));
- COMPLETIONS = UNSAFE.objectFieldOffset
- (k.getDeclaredField("completions"));
- } catch (Exception e) {
- throw new Error(e);
+ RESULT = u.objectFieldOffset(k.getDeclaredField("result"));
+ STACK = u.objectFieldOffset(k.getDeclaredField("stack"));
+ NEXT = u.objectFieldOffset
+ (Completion.class.getDeclaredField("next"));
+ } catch (Exception x) {
+ throw new Error(x);
}
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CompletionStage.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CompletionStage.java Wed Jul 05 19:59:54 2017 +0200
@@ -407,7 +407,7 @@
/**
* Returns a new CompletionStage that, when this and the other
* given stage complete normally, executes the given action using
- * the supplied executor
+ * the supplied executor.
*
* See the {@link CompletionStage} documentation for rules
* covering exceptional completion.
@@ -569,7 +569,7 @@
/**
* Returns a new CompletionStage that, when either this or the
* other given stage complete normally, executes the given action
- * using supplied executor.
+ * using the supplied executor.
*
* See the {@link CompletionStage} documentation for rules
* covering exceptional completion.
@@ -649,10 +649,15 @@
(Function<Throwable, ? extends T> fn);
/**
- * Returns a new CompletionStage with the same result or exception
- * as this stage, and when this stage completes, executes the
- * given action with the result (or {@code null} if none) and the
- * exception (or {@code null} if none) of this stage.
+ * Returns a new CompletionStage with the same result or exception as
+ * this stage, that executes the given action when this stage completes.
+ *
+ * <p>When this stage is complete, the given action is invoked with the
+ * result (or {@code null} if none) and the exception (or {@code null}
+ * if none) of this stage as arguments. The returned stage is completed
+ * when the action returns. If the supplied action itself encounters an
+ * exception, then the returned stage exceptionally completes with this
+ * exception unless this stage also completed exceptionally.
*
* @param action the action to perform
* @return the new CompletionStage
@@ -661,12 +666,16 @@
(BiConsumer<? super T, ? super Throwable> action);
/**
- * Returns a new CompletionStage with the same result or exception
- * as this stage, and when this stage completes, executes the
- * given action executes the given action using this stage's
- * default asynchronous execution facility, with the result (or
- * {@code null} if none) and the exception (or {@code null} if
- * none) of this stage as arguments.
+ * Returns a new CompletionStage with the same result or exception as
+ * this stage, that executes the given action using this stage's
+ * default asynchronous execution facility when this stage completes.
+ *
+ * <p>When this stage is complete, the given action is invoked with the
+ * result (or {@code null} if none) and the exception (or {@code null}
+ * if none) of this stage as arguments. The returned stage is completed
+ * when the action returns. If the supplied action itself encounters an
+ * exception, then the returned stage exceptionally completes with this
+ * exception unless this stage also completed exceptionally.
*
* @param action the action to perform
* @return the new CompletionStage
@@ -675,11 +684,16 @@
(BiConsumer<? super T, ? super Throwable> action);
/**
- * Returns a new CompletionStage with the same result or exception
- * as this stage, and when this stage completes, executes using
- * the supplied Executor, the given action with the result (or
- * {@code null} if none) and the exception (or {@code null} if
- * none) of this stage as arguments.
+ * Returns a new CompletionStage with the same result or exception as
+ * this stage, that executes the given action using the supplied
+ * Executor when this stage completes.
+ *
+ * <p>When this stage is complete, the given action is invoked with the
+ * result (or {@code null} if none) and the exception (or {@code null}
+ * if none) of this stage as arguments. The returned stage is completed
+ * when the action returns. If the supplied action itself encounters an
+ * exception, then the returned stage exceptionally completes with this
+ * exception unless this stage also completed exceptionally.
*
* @param action the action to perform
* @param executor the executor to use for asynchronous execution
@@ -693,9 +707,11 @@
* Returns a new CompletionStage that, when this stage completes
* either normally or exceptionally, is executed with this stage's
* result and exception as arguments to the supplied function.
- * The given function is invoked with the result (or {@code null}
- * if none) and the exception (or {@code null} if none) of this
- * stage when complete as arguments.
+ *
+ * <p>When this stage is complete, the given function is invoked
+ * with the result (or {@code null} if none) and the exception (or
+ * {@code null} if none) of this stage as arguments, and the
+ * function's result is used to complete the returned stage.
*
* @param fn the function to use to compute the value of the
* returned CompletionStage
@@ -710,9 +726,11 @@
* either normally or exceptionally, is executed using this stage's
* default asynchronous execution facility, with this stage's
* result and exception as arguments to the supplied function.
- * The given function is invoked with the result (or {@code null}
- * if none) and the exception (or {@code null} if none) of this
- * stage when complete as arguments.
+ *
+ * <p>When this stage is complete, the given function is invoked
+ * with the result (or {@code null} if none) and the exception (or
+ * {@code null} if none) of this stage as arguments, and the
+ * function's result is used to complete the returned stage.
*
* @param fn the function to use to compute the value of the
* returned CompletionStage
@@ -726,10 +744,12 @@
* Returns a new CompletionStage that, when this stage completes
* either normally or exceptionally, is executed using the
* supplied executor, with this stage's result and exception as
- * arguments to the supplied function. The given function is
- * invoked with the result (or {@code null} if none) and the
- * exception (or {@code null} if none) of this stage when complete
- * as arguments.
+ * arguments to the supplied function.
+ *
+ * <p>When this stage is complete, the given function is invoked
+ * with the result (or {@code null} if none) and the exception (or
+ * {@code null} if none) of this stage as arguments, and the
+ * function's result is used to complete the returned stage.
*
* @param fn the function to use to compute the value of the
* returned CompletionStage
--- a/jdk/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java Wed Jul 05 19:59:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2014, 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
@@ -158,8 +158,8 @@
// publicKey's format must be X.509 otherwise
// the whole CertGen part of this class is broken.
if (!"X.509".equalsIgnoreCase(publicKey.getFormat())) {
- throw new IllegalArgumentException("publicKey's is not X.509, but "
- + publicKey.getFormat());
+ throw new IllegalArgumentException("Public key format is "
+ + publicKey.getFormat() + ", must be X.509");
}
}
--- a/jdk/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java Wed Jul 05 19:59:54 2017 +0200
@@ -25,20 +25,20 @@
package sun.util.cldr;
-import java.io.File;
import java.security.AccessController;
-import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
import java.text.spi.BreakIteratorProvider;
import java.text.spi.CollatorProvider;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
-import java.util.ResourceBundle;
+import java.util.ServiceLoader;
import java.util.Set;
import java.util.StringTokenizer;
-import java.util.spi.TimeZoneNameProvider;
import sun.util.locale.provider.JRELocaleProviderAdapter;
import sun.util.locale.provider.LocaleProviderAdapter;
+import sun.util.locale.provider.LocaleDataMetaInfo;
/**
* LocaleProviderAdapter implementation for the CLDR locale data.
@@ -47,26 +47,31 @@
* @author Naoto Sato
*/
public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter {
- private static final String LOCALE_DATA_JAR_NAME = "cldrdata.jar";
+
+ private final LocaleDataMetaInfo metaInfo;
public CLDRLocaleProviderAdapter() {
- final String sep = File.separator;
- String localeDataJar = java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction("java.home"))
- + sep + "lib" + sep + "ext" + sep + LOCALE_DATA_JAR_NAME;
-
- // Peek at the installed extension directory to see if the jar file for
- // CLDR resources is installed or not.
- final File f = new File(localeDataJar);
- boolean result = AccessController.doPrivileged(
- new PrivilegedAction<Boolean>() {
+ try {
+ metaInfo = AccessController.doPrivileged(new PrivilegedExceptionAction<LocaleDataMetaInfo>() {
@Override
- public Boolean run() {
- return f.exists();
+ public LocaleDataMetaInfo run() {
+ for (LocaleDataMetaInfo ldmi : ServiceLoader.loadInstalled(LocaleDataMetaInfo.class)) {
+ if (ldmi.getType() == LocaleProviderAdapter.Type.CLDR) {
+ return ldmi;
+ }
+ }
+ return null;
}
});
- if (!result) {
- throw new UnsupportedOperationException();
+ } catch (Exception e) {
+ // Catch any exception, and fail gracefully as if CLDR locales do not exist.
+ // It's ok ignore it if something wrong happens because there always is the
+ // JRE or FALLBACK LocaleProviderAdapter that will do the right thing.
+ throw new UnsupportedOperationException(e);
+ }
+
+ if (metaInfo == null) {
+ throw new UnsupportedOperationException("CLDR locale data could not be found.");
}
}
@@ -91,7 +96,7 @@
@Override
public Locale[] getAvailableLocales() {
- Set<String> all = createLanguageTagSet("All");
+ Set<String> all = createLanguageTagSet("AvailableLocales");
Locale[] locs = new Locale[all.size()];
int index = 0;
for (String tag : all) {
@@ -102,11 +107,10 @@
@Override
protected Set<String> createLanguageTagSet(String category) {
- ResourceBundle rb = ResourceBundle.getBundle("sun.util.cldr.CLDRLocaleDataMetaInfo", Locale.ROOT);
- if (rb.containsKey(category)) {
+ String supportedLocaleString = metaInfo.availableLanguageTags(category);
+ if (supportedLocaleString == null) {
return Collections.emptySet();
}
- String supportedLocaleString = rb.getString(category);
Set<String> tagset = new HashSet<>();
StringTokenizer tokens = new StringTokenizer(supportedLocaleString);
while (tokens.hasMoreTokens()) {
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/AuxLocaleProviderAdapter.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/AuxLocaleProviderAdapter.java Wed Jul 05 19:59:54 2017 +0200
@@ -56,7 +56,7 @@
/**
* SPI implementations map
*/
- private ConcurrentMap<Class<? extends LocaleServiceProvider>, LocaleServiceProvider> providersMap =
+ private final ConcurrentMap<Class<? extends LocaleServiceProvider>, LocaleServiceProvider> providersMap =
new ConcurrentHashMap<>();
/**
@@ -167,7 +167,6 @@
avail.addAll(Arrays.asList(lsp.getAvailableLocales()));
}
}
- availableLocales = avail.toArray(new Locale[0]);
}
// assuming caller won't mutate the array.
@@ -178,7 +177,7 @@
* A dummy locale service provider that indicates there is no
* provider available
*/
- private static NullProvider NULL_PROVIDER = new NullProvider();
+ private static final NullProvider NULL_PROVIDER = new NullProvider();
private static class NullProvider extends LocaleServiceProvider {
@Override
public Locale[] getAvailableLocales() {
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java Wed Jul 05 19:59:54 2017 +0200
@@ -25,9 +25,9 @@
package sun.util.locale.provider;
-import java.io.File;
import java.security.AccessController;
-import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
import java.text.spi.BreakIteratorProvider;
import java.text.spi.CollatorProvider;
import java.text.spi.DateFormatProvider;
@@ -37,6 +37,7 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
+import java.util.ServiceLoader;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
@@ -58,8 +59,6 @@
*/
public class JRELocaleProviderAdapter extends LocaleProviderAdapter implements ResourceBundleBasedAdapter {
- private static final String LOCALE_DATA_JAR_NAME = "localedata.jar";
-
private final ConcurrentMap<String, Set<String>> langtagSets
= new ConcurrentHashMap<>();
@@ -356,26 +355,56 @@
}
protected Set<String> createLanguageTagSet(String category) {
- String supportedLocaleString = LocaleDataMetaInfo.getSupportedLocaleString(category);
+ String supportedLocaleString = createSupportedLocaleString(category);
if (supportedLocaleString == null) {
return Collections.emptySet();
}
Set<String> tagset = new HashSet<>();
StringTokenizer tokens = new StringTokenizer(supportedLocaleString);
while (tokens.hasMoreTokens()) {
- String token = tokens.nextToken();
- if (token.equals("|")) {
- if (isNonENLangSupported()) {
- continue;
- }
- break;
- }
- tagset.add(token);
+ tagset.add(tokens.nextToken());
}
return tagset;
}
+ private static String createSupportedLocaleString(String category) {
+ // Directly call English tags, as we know it's in the base module.
+ String supportedLocaleString = EnLocaleDataMetaInfo.getSupportedLocaleString(category);
+
+ // Use ServiceLoader to dynamically acquire installed locales' tags.
+ try {
+ String nonENTags = AccessController.doPrivileged(new PrivilegedExceptionAction<String>() {
+ @Override
+ public String run() {
+ String tags = null;
+ for (LocaleDataMetaInfo ldmi :
+ ServiceLoader.loadInstalled(LocaleDataMetaInfo.class)) {
+ if (ldmi.getType() == LocaleProviderAdapter.Type.JRE) {
+ String t = ldmi.availableLanguageTags(category);
+ if (t != null) {
+ if (tags == null) {
+ tags = t;
+ } else {
+ tags += " " + t;
+ }
+ }
+ }
+ }
+ return tags;
+ }
+ });
+
+ if (nonENTags != null) {
+ supportedLocaleString += " " + nonENTags;
+ }
+ } catch (Exception e) {
+ // catch any exception, and ignore them as if non-EN locales do not exist.
+ }
+
+ return supportedLocaleString;
+ }
+
/**
* Lazy load available locales.
*/
@@ -387,27 +416,17 @@
private static Locale[] createAvailableLocales() {
/*
- * Gets the locale string list from LocaleDataMetaInfo class and then
+ * Gets the locale string list from LocaleDataMetaInfo classes and then
* contructs the Locale array and a set of language tags based on the
* locale string returned above.
*/
- String supportedLocaleString = LocaleDataMetaInfo.getSupportedLocaleString("AvailableLocales");
+ String supportedLocaleString = createSupportedLocaleString("AvailableLocales");
if (supportedLocaleString.length() == 0) {
throw new InternalError("No available locales for JRE");
}
- /*
- * Look for "|" and construct a new locale string list.
- */
- int barIndex = supportedLocaleString.indexOf('|');
- StringTokenizer localeStringTokenizer;
- if (isNonENLangSupported()) {
- localeStringTokenizer = new StringTokenizer(supportedLocaleString.substring(0, barIndex)
- + supportedLocaleString.substring(barIndex + 1));
- } else {
- localeStringTokenizer = new StringTokenizer(supportedLocaleString.substring(0, barIndex));
- }
+ StringTokenizer localeStringTokenizer = new StringTokenizer(supportedLocaleString);
int length = localeStringTokenizer.countTokens();
Locale[] locales = new Locale[length + 1];
@@ -430,39 +449,4 @@
}
return locales;
}
-
- private static volatile Boolean isNonENSupported = null;
-
- /*
- * Returns true if the non EN resources jar file exists in jre
- * extension directory. @returns true if the jar file is there. Otherwise,
- * returns false.
- */
- private static boolean isNonENLangSupported() {
- if (isNonENSupported == null) {
- synchronized (JRELocaleProviderAdapter.class) {
- if (isNonENSupported == null) {
- final String sep = File.separator;
- String localeDataJar =
- java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction("java.home"))
- + sep + "lib" + sep + "ext" + sep + LOCALE_DATA_JAR_NAME;
-
- /*
- * Peek at the installed extension directory to see if
- * localedata.jar is installed or not.
- */
- final File f = new File(localeDataJar);
- isNonENSupported =
- AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
- @Override
- public Boolean run() {
- return f.exists();
}
- });
- }
- }
- }
- return isNonENSupported;
- }
-}
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template Wed Jul 05 19:59:54 2017 +0200
@@ -30,19 +30,17 @@
* each resource in sun.util.resources & sun.text.resources.
* It is used to avoid loading non-existent localized resources so that
* jar files won't be opened unnecessary to look up them.
- *
- * @since 1.6
*/
-package sun.util.locale.provider;
+package #Package#;
import java.util.HashMap;
-
-
-public class LocaleDataMetaInfo {
+import java.util.Map;
+import sun.util.locale.provider.LocaleDataMetaInfo;
+import static sun.util.locale.provider.LocaleProviderAdapter.Type;
- private static final HashMap<String, String> resourceNameToLocales =
- new HashMap<String, String>(7);
+public class #Lang#LocaleDataMetaInfo implements LocaleDataMetaInfo {
+ private static final Map<String, String> resourceNameToLocales = new HashMap<>(9);
static {
/* During JDK build time, #XXX_YYY# will be replaced by a string contain all the locales
@@ -52,38 +50,51 @@
look up locale string such as "en" could be based on if it contains " en ".
*/
resourceNameToLocales.put("FormatData",
- " #FormatData_ENLocales# | #FormatData_NonENLocales# ");
+ " #FormatData_Locales# ");
resourceNameToLocales.put("CollationData",
- " #CollationData_ENLocales# | #CollationData_NonENLocales# ");
+ " #CollationData_Locales# ");
resourceNameToLocales.put("BreakIteratorInfo",
- " #BreakIteratorInfo_ENLocales# | #BreakIteratorInfo_NonENLocales# ");
+ " #BreakIteratorInfo_Locales# ");
resourceNameToLocales.put("BreakIteratorRules",
- " #BreakIteratorRules_ENLocales# | #BreakIteratorRules_NonENLocales# ");
+ " #BreakIteratorRules_Locales# ");
resourceNameToLocales.put("TimeZoneNames",
- " #TimeZoneNames_ENLocales# | #TimeZoneNames_NonENLocales# ");
+ " #TimeZoneNames_Locales# ");
resourceNameToLocales.put("LocaleNames",
- " #LocaleNames_ENLocales# | #LocaleNames_NonENLocales# ");
+ " #LocaleNames_Locales# ");
resourceNameToLocales.put("CurrencyNames",
- " #CurrencyNames_ENLocales# | #CurrencyNames_NonENLocales# ");
+ " #CurrencyNames_Locales# ");
resourceNameToLocales.put("CalendarData",
- " #CalendarData_ENLocales# | #CalendarData_NonENLocales# ");
+ " #CalendarData_Locales# ");
resourceNameToLocales.put("AvailableLocales",
- " #AvailableLocales_ENLocales# | #AvailableLocales_NonENLocales# ");
+ " #AvailableLocales_Locales# ");
}
/*
+ * Gets the supported locales string based on the availability of
+ * locale data resource bundles for each resource name.
+ *
* @param resourceName the resource name
* @return the supported locale string for the passed in resource.
*/
public static String getSupportedLocaleString(String resourceName) {
- return resourceNameToLocales.get(resourceName);
+ return resourceNameToLocales.getOrDefault(resourceName, "");
+ }
+
+ @Override
+ public Type getType() {
+ return Type.JRE;
+}
+
+ @Override
+ public String availableLanguageTags(String category) {
+ return getSupportedLocaleString(category);
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, 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 sun.util.locale.provider;
+
+/**
+ * LocaleData meta info SPI
+ *
+ * @author Naoto Sato
+ */
+public interface LocaleDataMetaInfo {
+
+ /**
+ * Returns the type of LocaleProviderAdapter for which this LocaleData
+ * provides the data.
+ * @return type The type of the adapter.
+ */
+ public LocaleProviderAdapter.Type getType();
+
+ /**
+ * Returns the string concatenation of the supported language tags in
+ * this LocaleData instance
+ * @param category category of the locale data.
+ * @return concatenated language tags, separated by a space.
+ */
+ public String availableLanguageTags(String category);
+}
--- a/jdk/src/java.base/share/classes/sun/util/resources/LocaleData.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/resources/LocaleData.java Wed Jul 05 19:59:54 2017 +0200
@@ -50,7 +50,6 @@
import java.util.ResourceBundle;
import java.util.Set;
import sun.util.locale.provider.JRELocaleProviderAdapter;
-import sun.util.locale.provider.LocaleDataMetaInfo;
import sun.util.locale.provider.LocaleProviderAdapter;
import static sun.util.locale.provider.LocaleProviderAdapter.Type.CLDR;
import static sun.util.locale.provider.LocaleProviderAdapter.Type.JRE;
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWLightweightFramePeer.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWLightweightFramePeer.java Wed Jul 05 19:59:54 2017 +0200
@@ -94,10 +94,12 @@
@Override
public void addDropTarget(DropTarget dt) {
+ getLwTarget().addDropTarget(dt);
}
@Override
public void removeDropTarget(DropTarget dt) {
+ getLwTarget().removeDropTarget(dt);
}
@Override
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java Wed Jul 05 19:59:54 2017 +0200
@@ -688,6 +688,11 @@
@Override
public DragSourceContextPeer createDragSourceContextPeer(
DragGestureEvent dge) throws InvalidDnDOperationException {
+ final LightweightFrame f = SunToolkit.getLightweightFrame(dge.getComponent());
+ if (f != null) {
+ return f.createDragSourceContextPeer(dge);
+ }
+
return CDragSourceContextPeer.createDragSourceContextPeer(dge);
}
@@ -696,6 +701,11 @@
public <T extends DragGestureRecognizer> T createDragGestureRecognizer(
Class<T> abstractRecognizerClass, DragSource ds, Component c,
int srcActions, DragGestureListener dgl) {
+ final LightweightFrame f = SunToolkit.getLightweightFrame(c);
+ if (f != null) {
+ return f.createDragGestureRecognizer(abstractRecognizerClass, ds, c, srcActions, dgl);
+ }
+
DragGestureRecognizer dgr = null;
// Create a new mouse drag gesture recognizer if we have a class match:
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ja.properties Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ja.properties Wed Jul 05 19:59:54 2017 +0200
@@ -42,13 +42,13 @@
FileChooser.renameErrorFileExists.textAndMnemonic={0}\u306E\u540D\u524D\u3092\u5909\u66F4\u3067\u304D\u307E\u305B\u3093: \u6307\u5B9A\u3057\u305F\u540D\u524D\u306E\u30D5\u30A1\u30A4\u30EB\u306F\u3059\u3067\u306B\u5B58\u5728\u3057\u307E\u3059\u3002\u5225\u306E\u30D5\u30A1\u30A4\u30EB\u540D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002
FileChooser.acceptAllFileFilter.textAndMnemonic=\u3059\u3079\u3066\u306E\u30D5\u30A1\u30A4\u30EB
FileChooser.cancelButton.textAndMnemonic=\u53D6\u6D88
-FileChooser.saveButton.textAndMnemonic=\u4FDD\u5B58(&S)
-FileChooser.openButton.textAndMnemonic=\u958B\u304F(&O)
+FileChooser.saveButton.textAndMnemonic=\u4FDD\u5B58
+FileChooser.openButton.textAndMnemonic=\u958B\u304F
FileChooser.saveDialogTitle.textAndMnemonic=\u4FDD\u5B58
FileChooser.openDialogTitle.textAndMnemonic=\u958B\u304F
FileChooser.updateButton.textAndMnemonic=\u66F4\u65B0(&U)
FileChooser.helpButton.textAndMnemonic=\u30D8\u30EB\u30D7(&H)
-FileChooser.directoryOpenButton.textAndMnemonic=\u958B\u304F(&O)
+FileChooser.directoryOpenButton.textAndMnemonic=\u958B\u304F
# File Size Units
FileChooser.fileSizeKiloBytes={0} KB
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ko.properties Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ko.properties Wed Jul 05 19:59:54 2017 +0200
@@ -42,13 +42,13 @@
FileChooser.renameErrorFileExists.textAndMnemonic={0}\uC758 \uC774\uB984\uC744 \uBC14\uAFC0 \uC218 \uC5C6\uC74C: \uC9C0\uC815\uD55C \uC774\uB984\uC744 \uC0AC\uC6A9\uD558\uB294 \uD30C\uC77C\uC774 \uC874\uC7AC\uD569\uB2C8\uB2E4. \uB2E4\uB978 \uD30C\uC77C \uC774\uB984\uC744 \uC9C0\uC815\uD558\uC2ED\uC2DC\uC624.
FileChooser.acceptAllFileFilter.textAndMnemonic=\uBAA8\uB4E0 \uD30C\uC77C
FileChooser.cancelButton.textAndMnemonic=\uCDE8\uC18C
-FileChooser.saveButton.textAndMnemonic=\uC800\uC7A5(&S)
-FileChooser.openButton.textAndMnemonic=\uC5F4\uAE30(&O)
+FileChooser.saveButton.textAndMnemonic=\uC800\uC7A5
+FileChooser.openButton.textAndMnemonic=\uC5F4\uAE30
FileChooser.saveDialogTitle.textAndMnemonic=\uC800\uC7A5
FileChooser.openDialogTitle.textAndMnemonic=\uC5F4\uAE30
FileChooser.updateButton.textAndMnemonic=\uC5C5\uB370\uC774\uD2B8(&U)
FileChooser.helpButton.textAndMnemonic=\uB3C4\uC6C0\uB9D0(&H)
-FileChooser.directoryOpenButton.textAndMnemonic=\uC5F4\uAE30(&O)
+FileChooser.directoryOpenButton.textAndMnemonic=\uC5F4\uAE30
# File Size Units
FileChooser.fileSizeKiloBytes={0} KB
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_CN.properties Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_CN.properties Wed Jul 05 19:59:54 2017 +0200
@@ -42,13 +42,13 @@
FileChooser.renameErrorFileExists.textAndMnemonic=\u65E0\u6CD5\u91CD\u547D\u540D{0}: \u5DF2\u5B58\u5728\u5177\u6709\u6240\u6307\u5B9A\u540D\u79F0\u7684\u6587\u4EF6\u3002\u8BF7\u6307\u5B9A\u5176\u4ED6\u6587\u4EF6\u540D\u3002
FileChooser.acceptAllFileFilter.textAndMnemonic=\u6240\u6709\u6587\u4EF6
FileChooser.cancelButton.textAndMnemonic=\u53D6\u6D88
-FileChooser.saveButton.textAndMnemonic=\u4FDD\u5B58(&S)
-FileChooser.openButton.textAndMnemonic=\u6253\u5F00(&O)
+FileChooser.saveButton.textAndMnemonic=\u4FDD\u5B58
+FileChooser.openButton.textAndMnemonic=\u6253\u5F00
FileChooser.saveDialogTitle.textAndMnemonic=\u4FDD\u5B58
FileChooser.openDialogTitle.textAndMnemonic=\u6253\u5F00
FileChooser.updateButton.textAndMnemonic=\u66F4\u65B0(&U)
FileChooser.helpButton.textAndMnemonic=\u5E2E\u52A9(&H)
-FileChooser.directoryOpenButton.textAndMnemonic=\u6253\u5F00(&O)
+FileChooser.directoryOpenButton.textAndMnemonic=\u6253\u5F00
# File Size Units
FileChooser.fileSizeKiloBytes={0} KB
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_TW.properties Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_TW.properties Wed Jul 05 19:59:54 2017 +0200
@@ -42,13 +42,13 @@
FileChooser.renameErrorFileExists.textAndMnemonic=\u7121\u6CD5\u91CD\u65B0\u547D\u540D {0}: \u5DF2\u7D93\u5B58\u5728\u60A8\u6240\u6307\u5B9A\u540D\u7A31\u7684\u6A94\u6848\u3002\u8ACB\u6307\u5B9A\u4E0D\u540C\u7684\u540D\u7A31\u3002
FileChooser.acceptAllFileFilter.textAndMnemonic=\u6240\u6709\u6A94\u6848
FileChooser.cancelButton.textAndMnemonic=\u53D6\u6D88
-FileChooser.saveButton.textAndMnemonic=\u5132\u5B58(&S)
-FileChooser.openButton.textAndMnemonic=\u958B\u555F(&O)
+FileChooser.saveButton.textAndMnemonic=\u5132\u5B58
+FileChooser.openButton.textAndMnemonic=\u958B\u555F
FileChooser.saveDialogTitle.textAndMnemonic=\u5132\u5B58
FileChooser.openDialogTitle.textAndMnemonic=\u958B\u555F
FileChooser.updateButton.textAndMnemonic=\u66F4\u65B0(&U)
FileChooser.helpButton.textAndMnemonic=\u8AAA\u660E(&H)
-FileChooser.directoryOpenButton.textAndMnemonic=\u958B\u555F(&O)
+FileChooser.directoryOpenButton.textAndMnemonic=\u958B\u555F
# File Size Units
FileChooser.fileSizeKiloBytes={0} KB
--- a/jdk/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java Wed Jul 05 19:59:54 2017 +0200
@@ -968,20 +968,22 @@
*/
public static ICC_Profile getInstance(String fileName) throws IOException {
ICC_Profile thisProfile;
- FileInputStream fis = null;
+ InputStream is = null;
File f = getProfileFile(fileName);
if (f != null) {
- fis = new FileInputStream(f);
+ is = new FileInputStream(f);
+ } else {
+ is = getStandardProfileInputStream(fileName);
}
- if (fis == null) {
+ if (is == null) {
throw new IOException("Cannot open file " + fileName);
}
- thisProfile = getInstance(fis);
+ thisProfile = getInstance(is);
- fis.close(); /* close the file */
+ is.close(); /* close the file */
return thisProfile;
}
@@ -1086,28 +1088,17 @@
void activateDeferredProfile() throws ProfileDataException {
byte profileData[];
- FileInputStream fis;
final String fileName = deferralInfo.filename;
profileActivator = null;
deferralInfo = null;
- PrivilegedAction<FileInputStream> pa = new PrivilegedAction<FileInputStream>() {
- public FileInputStream run() {
- File f = getStandardProfileFile(fileName);
- if (f != null) {
- try {
- return new FileInputStream(f);
- } catch (FileNotFoundException e) {}
- }
- return null;
- }
- };
- if ((fis = AccessController.doPrivileged(pa)) == null) {
+ InputStream is = getStandardProfileInputStream(fileName);
+ if (is == null) {
throw new ProfileDataException("Cannot open file " + fileName);
}
try {
- profileData = getProfileDataFromStream(fis);
- fis.close(); /* close the file */
+ profileData = getProfileDataFromStream(is);
+ is.close(); /* close the file */
}
catch (IOException e) {
ProfileDataException pde = new
@@ -1810,10 +1801,12 @@
* fileName may be an absolute or a relative file specification.
* Relative file names are looked for in several places: first, relative
* to any directories specified by the java.iccprofile.path property;
- * second, relative to any directories specified by the java.class.path
- * property; finally, in a directory used to store profiles always
- * available, such as a profile for sRGB. Built-in profiles use .pf as
- * the file name extension for profiles, e.g. sRGB.pf.
+ * second, relative to any directories specified by the java.class.path.
+ * The built-in profile files are now loaded as resources, since they
+ * may not be individual disk files, and so this method will not find
+ * these and on a null return, the caller needs to try as resources.
+ * Built-in profiles use .pf as the file name extension for profiles,
+ * e.g. sRGB.pf.
*/
private static File getProfileFile(String fileName) {
String path, dir, fullPath;
@@ -1849,30 +1842,22 @@
fullPath = dir + File.separatorChar + fileName;
f = new File(fullPath);
}
- }
+ }
- if ((f == null) || (!f.isFile())) {
- /* try the directory of built-in profiles */
- f = getStandardProfileFile(fileName);
+ if (f != null && !f.isFile()) {
+ f = null;
}
- if (f != null && f.isFile()) {
- return f;
- }
- return null;
+ return f;
}
/**
- * Returns a file object corresponding to a built-in profile
+ * Returns a stream corresponding to a built-in profile
* specified by fileName.
* If there is no built-in profile with such name, then the method
* returns null.
*/
- private static File getStandardProfileFile(String fileName) {
- String dir = System.getProperty("java.home") +
- File.separatorChar + "lib" + File.separatorChar + "cmm";
- String fullPath = dir + File.separatorChar + fileName;
- File f = new File(fullPath);
- return (f.isFile() && isChildOf(f, dir)) ? f : null;
+ private static InputStream getStandardProfileInputStream(String fileName) {
+ return PCMM.class.getResourceAsStream("profiles/" + fileName);
}
/**
@@ -1901,7 +1886,7 @@
private static boolean standardProfileExists(final String fileName) {
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
public Boolean run() {
- return getStandardProfileFile(fileName) != null;
+ return PCMM.class.getResource("profiles/"+fileName) != null;
}
});
}
--- a/jdk/src/java.desktop/share/classes/javax/imageio/ImageReader.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/ImageReader.java Wed Jul 05 19:59:54 2017 +0200
@@ -2806,7 +2806,7 @@
* @param imageTypes an <code>Iterator</code> of
* <code>ImageTypeSpecifier</code>s indicating the legal image
* types, with the default first.
- * @param width the true width of the image or tile begin decoded.
+ * @param width the true width of the image or tile being decoded.
* @param height the true width of the image or tile being decoded.
*
* @return the <code>BufferedImage</code> to which decoded pixel
--- a/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataNode.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataNode.java Wed Jul 05 19:59:54 2017 +0200
@@ -305,6 +305,9 @@
/**
* Check that the node is either <code>null</code> or an
* <code>IIOMetadataNode</code>.
+ *
+ * @throws DOMException if {@code node} is not {@code null} and not an
+ * instance of {@code IIOMetadataNode}
*/
private void checkNode(Node node) throws DOMException {
if (node == null) {
--- a/jdk/src/java.desktop/share/classes/javax/print/attribute/standard/DialogTypeSelection.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/print/attribute/standard/DialogTypeSelection.java Wed Jul 05 19:59:54 2017 +0200
@@ -67,7 +67,7 @@
COMMON = new DialogTypeSelection(1);
/**
- * Construct a new dialog type selection enumeration value with the
+ * Constructs a new dialog type selection enumeration value with the
* given integer value.
*
* @param value Integer value.
@@ -101,7 +101,7 @@
/**
- * Get the printing attribute class which is to be used as the "category"
+ * Gets the printing attribute class which is to be used as the "category"
* for this printing attribute value.
* <P>
* For class DialogTypeSelection the category is class
@@ -116,7 +116,7 @@
/**
- * Get the name of the category of which this attribute value is an
+ * Gets the name of the category of which this attribute value is an
* instance.
* <P>
* For class DialogTypeSelection the category name is
--- a/jdk/src/java.desktop/share/classes/javax/swing/JSlider.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JSlider.java Wed Jul 05 19:59:54 2017 +0200
@@ -138,8 +138,11 @@
/**
* {@code Dictionary} of what labels to draw at which values
*/
- private Dictionary<Integer, JComponent> labelTable;
-
+ @SuppressWarnings("rawtypes")
+ private Dictionary labelTable;
+ // For better source compatibility, the labelTable field and
+ // associated getter and setter methods are being left as raw
+ // types.
/**
* The changeListener (no suffix) is the listener we add to the
@@ -773,10 +776,10 @@
}
// Check that there is a label with such image
- Enumeration<JComponent> elements = labelTable.elements();
+ Enumeration<?> elements = labelTable.elements();
while (elements.hasMoreElements()) {
- JComponent component = elements.nextElement();
+ Component component = (Component) elements.nextElement();
if (component instanceof JLabel) {
JLabel label = (JLabel) component;
@@ -797,7 +800,8 @@
* @return the <code>Dictionary</code> containing labels and
* where to draw them
*/
- public Dictionary<Integer, JComponent> getLabelTable() {
+ @SuppressWarnings("rawtypes")
+ public Dictionary getLabelTable() {
/*
if ( labelTable == null && getMajorTickSpacing() > 0 ) {
setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
@@ -830,8 +834,9 @@
* attribute: visualUpdate true
* description: Specifies what labels will be drawn for any given value.
*/
- public void setLabelTable( Dictionary<Integer, JComponent> labels ) {
- Dictionary<Integer, JComponent> oldTable = labelTable;
+ @SuppressWarnings("rawtypes")
+ public void setLabelTable( Dictionary labels ) {
+ Dictionary oldTable = labelTable;
labelTable = labels;
updateLabelUIs();
firePropertyChange("labelTable", oldTable, labelTable );
@@ -852,25 +857,27 @@
* @see JComponent#updateUI
*/
protected void updateLabelUIs() {
- Dictionary<Integer, JComponent> labelTable = getLabelTable();
+ @SuppressWarnings("rawtypes")
+ Dictionary labelTable = getLabelTable();
if (labelTable == null) {
return;
}
- Enumeration<Integer> labels = labelTable.keys();
+ Enumeration<?> labels = labelTable.keys();
while ( labels.hasMoreElements() ) {
- JComponent component = labelTable.get(labels.nextElement());
+ JComponent component = (JComponent) labelTable.get(labels.nextElement());
component.updateUI();
component.setSize(component.getPreferredSize());
}
}
private void updateLabelSizes() {
- Dictionary<Integer, JComponent> labelTable = getLabelTable();
+ @SuppressWarnings("rawtypes")
+ Dictionary labelTable = getLabelTable();
if (labelTable != null) {
- Enumeration<JComponent> labels = labelTable.elements();
+ Enumeration<?> labels = labelTable.elements();
while (labels.hasMoreElements()) {
- JComponent component = labels.nextElement();
+ JComponent component = (JComponent) labels.nextElement();
component.setSize(component.getPreferredSize());
}
}
@@ -982,13 +989,13 @@
if ( e.getPropertyName().equals( "minimum" ) ||
e.getPropertyName().equals( "maximum" ) ) {
- Enumeration<Integer> keys = getLabelTable().keys();
+ Enumeration<?> keys = getLabelTable().keys();
Hashtable<Integer, JComponent> hashtable = new Hashtable<>();
// Save the labels that were added by the developer
while ( keys.hasMoreElements() ) {
- Integer key = keys.nextElement();
- JComponent value = labelTable.get(key);
+ Integer key = (Integer) keys.nextElement();
+ JComponent value = (JComponent) labelTable.get(key);
if ( !(value instanceof LabelUIResource) ) {
hashtable.put( key, value );
}
@@ -1000,7 +1007,7 @@
// Add the saved labels
keys = hashtable.keys();
while ( keys.hasMoreElements() ) {
- Integer key = keys.nextElement();
+ Integer key = (Integer) keys.nextElement();
put( key, hashtable.get( key ) );
}
@@ -1017,7 +1024,8 @@
SmartHashtable table = new SmartHashtable( increment, start );
- Dictionary<Integer, JComponent> labelTable = getLabelTable();
+ @SuppressWarnings("rawtypes")
+ Dictionary labelTable = getLabelTable();
if (labelTable != null && (labelTable instanceof PropertyChangeListener)) {
removePropertyChangeListener((PropertyChangeListener) labelTable);
--- a/jdk/src/java.desktop/share/classes/javax/swing/JTable.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JTable.java Wed Jul 05 19:59:54 2017 +0200
@@ -670,7 +670,8 @@
* @param rowData the data for the new table
* @param columnNames names of each column
*/
- public JTable(Vector<Vector<Object>> rowData, Vector<Object> columnNames) {
+ @SuppressWarnings("rawtypes")
+ public JTable(Vector<? extends Vector> rowData, Vector<?> columnNames) {
this(new DefaultTableModel(rowData, columnNames));
}
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSliderUI.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSliderUI.java Wed Jul 05 19:59:54 2017 +0200
@@ -397,13 +397,14 @@
protected boolean labelsHaveSameBaselines() {
if (!checkedLabelBaselines) {
checkedLabelBaselines = true;
- Dictionary<?, JComponent> dictionary = slider.getLabelTable();
+ @SuppressWarnings("rawtypes")
+ Dictionary dictionary = slider.getLabelTable();
if (dictionary != null) {
sameLabelBaselines = true;
- Enumeration<JComponent> elements = dictionary.elements();
+ Enumeration<?> elements = dictionary.elements();
int baseline = -1;
while (elements.hasMoreElements()) {
- JComponent label = elements.nextElement();
+ JComponent label = (JComponent) elements.nextElement();
Dimension pref = label.getPreferredSize();
int labelBaseline = label.getBaseline(pref.width,
pref.height);
@@ -758,12 +759,13 @@
}
protected int getWidthOfWidestLabel() {
- Dictionary<?, JComponent> dictionary = slider.getLabelTable();
+ @SuppressWarnings("rawtypes")
+ Dictionary dictionary = slider.getLabelTable();
int widest = 0;
if ( dictionary != null ) {
Enumeration<?> keys = dictionary.keys();
while ( keys.hasMoreElements() ) {
- JComponent label = dictionary.get(keys.nextElement());
+ JComponent label = (JComponent) dictionary.get(keys.nextElement());
widest = Math.max( label.getPreferredSize().width, widest );
}
}
@@ -771,12 +773,13 @@
}
protected int getHeightOfTallestLabel() {
- Dictionary<?, JComponent> dictionary = slider.getLabelTable();
+ @SuppressWarnings("rawtypes")
+ Dictionary dictionary = slider.getLabelTable();
int tallest = 0;
if ( dictionary != null ) {
Enumeration<?> keys = dictionary.keys();
while ( keys.hasMoreElements() ) {
- JComponent label = dictionary.get(keys.nextElement());
+ JComponent label = (JComponent) dictionary.get(keys.nextElement());
tallest = Math.max( label.getPreferredSize().height, tallest );
}
}
@@ -847,18 +850,19 @@
* @since 1.6
*/
protected Integer getHighestValue() {
- Dictionary<Integer, ?> dictionary = slider.getLabelTable();
+ @SuppressWarnings("rawtypes")
+ Dictionary dictionary = slider.getLabelTable();
if (dictionary == null) {
return null;
}
- Enumeration<Integer> keys = dictionary.keys();
+ Enumeration<?> keys = dictionary.keys();
Integer max = null;
while (keys.hasMoreElements()) {
- Integer i = keys.nextElement();
+ Integer i = (Integer) keys.nextElement();
if (max == null || i > max) {
max = i;
@@ -876,18 +880,19 @@
* @since 1.6
*/
protected Integer getLowestValue() {
- Dictionary<Integer, JComponent> dictionary = slider.getLabelTable();
+ @SuppressWarnings("rawtypes")
+ Dictionary dictionary = slider.getLabelTable();
if (dictionary == null) {
return null;
}
- Enumeration<Integer> keys = dictionary.keys();
+ Enumeration<?> keys = dictionary.keys();
Integer min = null;
while (keys.hasMoreElements()) {
- Integer i = keys.nextElement();
+ Integer i = (Integer) keys.nextElement();
if (min == null || i < min) {
min = i;
@@ -1134,17 +1139,18 @@
public void paintLabels( Graphics g ) {
Rectangle labelBounds = labelRect;
- Dictionary<Integer, JComponent> dictionary = slider.getLabelTable();
+ @SuppressWarnings("rawtypes")
+ Dictionary dictionary = slider.getLabelTable();
if ( dictionary != null ) {
- Enumeration<Integer> keys = dictionary.keys();
+ Enumeration<?> keys = dictionary.keys();
int minValue = slider.getMinimum();
int maxValue = slider.getMaximum();
boolean enabled = slider.isEnabled();
while ( keys.hasMoreElements() ) {
- Integer key = keys.nextElement();
+ Integer key = (Integer)keys.nextElement();
int value = key.intValue();
if (value >= minValue && value <= maxValue) {
- JComponent label = dictionary.get(key);
+ JComponent label = (JComponent) dictionary.get(key);
label.setEnabled(enabled);
if (label instanceof JLabel) {
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSliderUI.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSliderUI.java Wed Jul 05 19:59:54 2017 +0200
@@ -269,7 +269,7 @@
centerY += valueHeight + 2;
centerY += trackHeight + trackInsets.top + trackInsets.bottom;
centerY += tickHeight + 2;
- JComponent label = slider.getLabelTable().elements().nextElement();
+ JComponent label = (JComponent) slider.getLabelTable().elements().nextElement();
Dimension pref = label.getPreferredSize();
return centerY + label.getBaseline(pref.width, pref.height);
}
@@ -291,7 +291,7 @@
int trackHeight = contentHeight - valueHeight;
int yPosition = yPositionForValue(value.intValue(), trackY,
trackHeight);
- JComponent label = slider.getLabelTable().get(value);
+ JComponent label = (JComponent) slider.getLabelTable().get(value);
Dimension pref = label.getPreferredSize();
return yPosition - pref.height / 2 +
label.getBaseline(pref.width, pref.height);
@@ -392,7 +392,8 @@
trackRect.x = insetCache.left;
trackRect.width = contentRect.width;
- Dictionary<Integer, JComponent> dictionary = slider.getLabelTable();
+ @SuppressWarnings("rawtypes")
+ Dictionary dictionary = slider.getLabelTable();
if (dictionary != null) {
int minValue = slider.getMinimum();
int maxValue = slider.getMaximum();
@@ -402,9 +403,9 @@
// slider range.
int firstLblIdx = Integer.MAX_VALUE;
int lastLblIdx = Integer.MIN_VALUE;
- for (Enumeration<Integer> keys = dictionary.keys();
+ for (Enumeration<?> keys = dictionary.keys();
keys.hasMoreElements(); ) {
- int keyInt = keys.nextElement().intValue();
+ int keyInt = ((Integer)keys.nextElement()).intValue();
if (keyInt >= minValue && keyInt < firstLblIdx) {
firstLblIdx = keyInt;
}
@@ -517,7 +518,7 @@
private int getPadForLabel(int i) {
int pad = 0;
- JComponent c = slider.getLabelTable().get(i);
+ JComponent c = (JComponent) slider.getLabelTable().get(i);
if (c != null) {
int centerX = xPositionForValue(i);
int cHalfWidth = c.getPreferredSize().width / 2;
--- a/jdk/src/java.desktop/share/classes/javax/swing/table/DefaultTableModel.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/table/DefaultTableModel.java Wed Jul 05 19:59:54 2017 +0200
@@ -70,10 +70,18 @@
* The <code>Vector</code> of <code>Vectors</code> of
* <code>Object</code> values.
*/
- protected Vector<Vector<Object>> dataVector;
+ @SuppressWarnings("rawtypes")
+ protected Vector<Vector> dataVector;
/** The <code>Vector</code> of column identifiers. */
- protected Vector<Object> columnIdentifiers;
+ @SuppressWarnings("rawtypes")
+ protected Vector columnIdentifiers;
+ // Unfortunately, for greater source compatibility the inner-most
+ // Vector in the two fields above is being left raw. The Vector is
+ // read as well as written so using Vector<?> is not suitable and
+ // using Vector<Object> (without adding copying of input Vectors),
+ // would disallow existing code that used, say, a Vector<String>
+ // as an input parameter.
//
// Constructors
@@ -121,7 +129,7 @@
* @see #setDataVector
* @see #setValueAt
*/
- public DefaultTableModel(Vector<Object> columnNames, int rowCount) {
+ public DefaultTableModel(Vector<?> columnNames, int rowCount) {
setDataVector(newVector(rowCount), columnNames);
}
@@ -156,7 +164,8 @@
* @see #getDataVector
* @see #setDataVector
*/
- public DefaultTableModel(Vector<Vector<Object>> data, Vector<Object> columnNames) {
+ @SuppressWarnings("rawtypes")
+ public DefaultTableModel(Vector<? extends Vector> data, Vector<?> columnNames) {
setDataVector(data, columnNames);
}
@@ -191,7 +200,8 @@
* @see #newRowsAdded
* @see #setDataVector
*/
- public Vector<Vector<Object>> getDataVector() {
+ @SuppressWarnings("rawtypes")
+ public Vector<Vector> getDataVector() {
return dataVector;
}
@@ -219,9 +229,10 @@
* @param columnIdentifiers the names of the columns
* @see #getDataVector
*/
- public void setDataVector(Vector<Vector<Object>> dataVector,
- Vector<Object> columnIdentifiers) {
- this.dataVector = nonNullVector(dataVector);
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public void setDataVector(Vector<? extends Vector> dataVector,
+ Vector<?> columnIdentifiers) {
+ this.dataVector = nonNullVector((Vector<Vector>)dataVector);
this.columnIdentifiers = nonNullVector(columnIdentifiers);
justifyRows(0, getRowCount());
fireTableStructureChanged();
@@ -267,7 +278,7 @@
if (dataVector.elementAt(i) == null) {
dataVector.setElementAt(new Vector<>(), i);
}
- ((Vector)dataVector.elementAt(i)).setSize(getColumnCount());
+ dataVector.elementAt(i).setSize(getColumnCount());
}
}
@@ -350,7 +361,7 @@
*
* @param rowData optional data of the row being added
*/
- public void addRow(Vector<Object> rowData) {
+ public void addRow(Vector<?> rowData) {
insertRow(getRowCount(), rowData);
}
@@ -374,7 +385,7 @@
* @param rowData optional data of the row being added
* @exception ArrayIndexOutOfBoundsException if the row was invalid
*/
- public void insertRow(int row, Vector<Object> rowData) {
+ public void insertRow(int row, Vector<?> rowData) {
dataVector.insertElementAt(rowData, row);
justifyRows(row, row+1);
fireTableRowsInserted(row, row);
@@ -484,7 +495,7 @@
* to zero columns
* @see #setNumRows
*/
- public void setColumnIdentifiers(Vector<Object> columnIdentifiers) {
+ public void setColumnIdentifiers(Vector<?> columnIdentifiers) {
setDataVector(dataVector, columnIdentifiers);
}
@@ -550,7 +561,8 @@
* @param columnName the identifier of the column being added
* @param columnData optional data of the column being added
*/
- public void addColumn(Object columnName, Vector<Object> columnData) {
+ @SuppressWarnings("unchecked") // Adding element to raw columnIdentifiers
+ public void addColumn(Object columnName, Vector<?> columnData) {
columnIdentifiers.addElement(columnName);
if (columnData != null) {
int columnSize = columnData.size();
@@ -652,6 +664,7 @@
* column was given
*/
public Object getValueAt(int row, int column) {
+ @SuppressWarnings("unchecked")
Vector<Object> rowVector = dataVector.elementAt(row);
return rowVector.elementAt(column);
}
@@ -668,6 +681,7 @@
* column was given
*/
public void setValueAt(Object aValue, int row, int column) {
+ @SuppressWarnings("unchecked")
Vector<Object> rowVector = dataVector.elementAt(row);
rowVector.setElementAt(aValue, column);
fireTableCellUpdated(row, column);
--- a/jdk/src/java.desktop/share/classes/javax/swing/tree/DefaultMutableTreeNode.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/tree/DefaultMutableTreeNode.java Wed Jul 05 19:59:54 2017 +0200
@@ -1317,7 +1317,7 @@
}
private final class PreorderEnumeration implements Enumeration<TreeNode> {
- private final Stack<Enumeration<TreeNode>> stack = new Stack<>();
+ private final Stack<Enumeration<? extends TreeNode>> stack = new Stack<>();
public PreorderEnumeration(TreeNode rootNode) {
super();
@@ -1331,10 +1331,9 @@
}
public TreeNode nextElement() {
- Enumeration<TreeNode> enumer = stack.peek();
+ Enumeration<? extends TreeNode> enumer = stack.peek();
TreeNode node = enumer.nextElement();
- @SuppressWarnings("unchecked")
- Enumeration<TreeNode> children = node.children();
+ Enumeration<? extends TreeNode> children = node.children();
if (!enumer.hasMoreElements()) {
stack.pop();
@@ -1351,7 +1350,7 @@
final class PostorderEnumeration implements Enumeration<TreeNode> {
protected TreeNode root;
- protected Enumeration<TreeNode> children;
+ protected Enumeration<? extends TreeNode> children;
protected Enumeration<TreeNode> subtree;
public PostorderEnumeration(TreeNode rootNode) {
--- a/jdk/src/java.desktop/share/classes/javax/swing/tree/TreeNode.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/tree/TreeNode.java Wed Jul 05 19:59:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, 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
@@ -99,5 +99,5 @@
*
* @return the children of the receiver as an {@code Enumeration}
*/
- Enumeration<TreeNode> children();
+ Enumeration<? extends TreeNode> children();
}
--- a/jdk/src/java.desktop/share/classes/sun/awt/LightweightFrame.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/LightweightFrame.java Wed Jul 05 19:59:54 2017 +0200
@@ -25,6 +25,7 @@
package sun.awt;
+import java.awt.Component;
import java.awt.Container;
import java.awt.Frame;
import java.awt.Graphics;
@@ -33,6 +34,13 @@
import java.awt.MenuComponent;
import java.awt.Rectangle;
import java.awt.Toolkit;
+import java.awt.dnd.DragGestureEvent;
+import java.awt.dnd.DragGestureListener;
+import java.awt.dnd.DragGestureRecognizer;
+import java.awt.dnd.DragSource;
+import java.awt.dnd.DropTarget;
+import java.awt.dnd.InvalidDnDOperationException;
+import java.awt.dnd.peer.DragSourceContextPeer;
import java.awt.peer.FramePeer;
/**
@@ -169,4 +177,27 @@
hostW = w;
hostH = h;
}
+
+ /**
+ * Create a drag gesture recognizer for the lightweight frame.
+ */
+ public abstract <T extends DragGestureRecognizer> T createDragGestureRecognizer(
+ Class<T> abstractRecognizerClass,
+ DragSource ds, Component c, int srcActions,
+ DragGestureListener dgl);
+
+ /**
+ * Create a drag source context peer for the lightweight frame.
+ */
+ public abstract DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException;
+
+ /**
+ * Adds a drop target to the lightweight frame.
+ */
+ public abstract void addDropTarget(DropTarget dt);
+
+ /**
+ * Removes a drop target from the lightweight frame.
+ */
+ public abstract void removeDropTarget(DropTarget dt);
}
--- a/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java Wed Jul 05 19:59:54 2017 +0200
@@ -2014,6 +2014,19 @@
return isInstanceOf(cls.getSuperclass(), type);
}
+ protected static LightweightFrame getLightweightFrame(Component c) {
+ for (; c != null; c = c.getParent()) {
+ if (c instanceof LightweightFrame) {
+ return (LightweightFrame)c;
+ }
+ if (c instanceof Window) {
+ // Don't traverse owner windows
+ return null;
+ }
+ }
+ return null;
+ }
+
///////////////////////////////////////////////////////////////////////////
//
// The following methods help set and identify whether a particular
--- a/jdk/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java Wed Jul 05 19:59:54 2017 +0200
@@ -187,7 +187,6 @@
public static native void colorConvert(LCMSTransform trans,
LCMSImageLayout src,
LCMSImageLayout dest);
- public static native void freeTransform(long ID);
public static native void initLCMS(Class<?> Trans, Class<?> IL, Class<?> Pf);
Binary file jdk/src/java.desktop/share/classes/sun/java2d/cmm/profiles/CIEXYZ.pf has changed
Binary file jdk/src/java.desktop/share/classes/sun/java2d/cmm/profiles/GRAY.pf has changed
Binary file jdk/src/java.desktop/share/classes/sun/java2d/cmm/profiles/LINEAR_RGB.pf has changed
Binary file jdk/src/java.desktop/share/classes/sun/java2d/cmm/profiles/PYCC.pf has changed
Binary file jdk/src/java.desktop/share/classes/sun/java2d/cmm/profiles/sRGB.pf has changed
--- a/jdk/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java Wed Jul 05 19:59:54 2017 +0200
@@ -37,6 +37,13 @@
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
+import java.awt.dnd.DragGestureEvent;
+import java.awt.dnd.DragGestureListener;
+import java.awt.dnd.DragGestureRecognizer;
+import java.awt.dnd.DragSource;
+import java.awt.dnd.DropTarget;
+import java.awt.dnd.InvalidDnDOperationException;
+import java.awt.dnd.peer.DragSourceContextPeer;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.awt.image.BufferedImage;
@@ -472,4 +479,27 @@
content.setCursor(target.getCursor());
}
}
+
+ public <T extends DragGestureRecognizer> T createDragGestureRecognizer(
+ Class<T> abstractRecognizerClass,
+ DragSource ds, Component c, int srcActions,
+ DragGestureListener dgl)
+ {
+ return content == null ? null : content.createDragGestureRecognizer(
+ abstractRecognizerClass, ds, c, srcActions, dgl);
+ }
+
+ public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException {
+ return content == null ? null : content.createDragSourceContextPeer(dge);
+ }
+
+ public void addDropTarget(DropTarget dt) {
+ if (content == null) return;
+ content.addDropTarget(dt);
+ }
+
+ public void removeDropTarget(DropTarget dt) {
+ if (content == null) return;
+ content.removeDropTarget(dt);
+ }
}
--- a/jdk/src/java.desktop/share/classes/sun/swing/LightweightContent.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/swing/LightweightContent.java Wed Jul 05 19:59:54 2017 +0200
@@ -26,7 +26,15 @@
package sun.swing;
import javax.swing.JComponent;
+import java.awt.Component;
import java.awt.Cursor;
+import java.awt.dnd.DragGestureEvent;
+import java.awt.dnd.DragGestureListener;
+import java.awt.dnd.DragGestureRecognizer;
+import java.awt.dnd.DragSource;
+import java.awt.dnd.DropTarget;
+import java.awt.dnd.InvalidDnDOperationException;
+import java.awt.dnd.peer.DragSourceContextPeer;
/**
* The interface by means of which the {@link JLightweightFrame} class
@@ -209,4 +217,33 @@
* @param cursor a cursor to set
*/
default public void setCursor(Cursor cursor) { }
+
+ /**
+ * Create a drag gesture recognizer for the lightweight frame.
+ */
+ default public <T extends DragGestureRecognizer> T createDragGestureRecognizer(
+ Class<T> abstractRecognizerClass,
+ DragSource ds, Component c, int srcActions,
+ DragGestureListener dgl)
+ {
+ return null;
+ }
+
+ /**
+ * Create a drag source context peer for the lightweight frame.
+ */
+ default public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException
+ {
+ return null;
+ }
+
+ /**
+ * Adds a drop target to the lightweight frame.
+ */
+ default public void addDropTarget(DropTarget dt) {}
+
+ /**
+ * Removes a drop target from the lightweight frame.
+ */
+ default public void removeDropTarget(DropTarget dt) {}
}
Binary file jdk/src/java.desktop/share/conf/cmm/lcms/CIEXYZ.pf has changed
Binary file jdk/src/java.desktop/share/conf/cmm/lcms/GRAY.pf has changed
Binary file jdk/src/java.desktop/share/conf/cmm/lcms/LINEAR_RGB.pf has changed
Binary file jdk/src/java.desktop/share/conf/cmm/lcms/PYCC.pf has changed
Binary file jdk/src/java.desktop/share/conf/cmm/lcms/sRGB.pf has changed
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XLightweightFramePeer.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XLightweightFramePeer.java Wed Jul 05 19:59:54 2017 +0200
@@ -26,6 +26,7 @@
package sun.awt.X11;
import java.awt.Graphics;
+import java.awt.dnd.DropTarget;
import sun.awt.LightweightFrame;
import sun.swing.JLightweightFrame;
@@ -69,4 +70,14 @@
public void updateCursorImmediately() {
SwingAccessor.getJLightweightFrameAccessor().updateCursor((JLightweightFrame)getLwTarget());
}
+
+ @Override
+ public void addDropTarget(DropTarget dt) {
+ getLwTarget().addDropTarget(dt);
+ }
+
+ @Override
+ public void removeDropTarget(DropTarget dt) {
+ getLwTarget().removeDropTarget(dt);
+ }
}
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java Wed Jul 05 19:59:54 2017 +0200
@@ -927,6 +927,11 @@
}
public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException {
+ final LightweightFrame f = SunToolkit.getLightweightFrame(dge.getComponent());
+ if (f != null) {
+ return f.createDragSourceContextPeer(dge);
+ }
+
return XDragSourceContextPeer.createDragSourceContextPeer(dge);
}
@@ -938,6 +943,11 @@
int srcActions,
DragGestureListener dgl)
{
+ final LightweightFrame f = SunToolkit.getLightweightFrame(c);
+ if (f != null) {
+ return f.createDragGestureRecognizer(recognizerClass, ds, c, srcActions, dgl);
+ }
+
if (MouseDragGestureRecognizer.class.equals(recognizerClass))
return (T)new XMouseDragGestureRecognizer(ds, c, srcActions, dgl);
else
--- a/jdk/src/java.desktop/unix/native/common/sun/awt/CUPSfuncs.c Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/unix/native/common/sun/awt/CUPSfuncs.c Wed Jul 05 19:59:54 2017 +0200
@@ -436,6 +436,7 @@
if (name == NULL) {
(*env)->ExceptionClear(env);
JNU_ThrowOutOfMemoryError(env, "Could not create printer name");
+ return;
}
const char *filename;
@@ -467,8 +468,11 @@
}
}
if (defx > 0) {
- jobject rxObj = (*env)->NewObject(env, intCls, intCtr, defx);
- jobject ryObj = (*env)->NewObject(env, intCls, intCtr, defy);
+ jobject rxObj, ryObj;
+ rxObj = (*env)->NewObject(env, intCls, intCtr, defx);
+ CHECK_NULL(rxObj);
+ ryObj = (*env)->NewObject(env, intCls, intCtr, defy);
+ CHECK_NULL(ryObj);
(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, rxObj);
(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, ryObj);
}
@@ -492,8 +496,11 @@
}
}
if (resx > 0 && (resx != defx || resy != defy )) {
- jobject rxObj = (*env)->NewObject(env, intCls, intCtr, resx);
- jobject ryObj = (*env)->NewObject(env, intCls, intCtr, resy);
+ jobject rxObj, ryObj;
+ rxObj = (*env)->NewObject(env, intCls, intCtr, resx);
+ CHECK_NULL(rxObj);
+ ryObj = (*env)->NewObject(env, intCls, intCtr, resy);
+ CHECK_NULL(ryObj);
(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, rxObj);
(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, ryObj);
}
--- a/jdk/src/java.desktop/unix/native/common/sun/awt/X11Color.c Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/unix/native/common/sun/awt/X11Color.c Wed Jul 05 19:59:54 2017 +0200
@@ -1377,7 +1377,7 @@
/* Unlock now to initialize the SystemColor class */
if (lock) {
- AWT_UNLOCK ();
+ AWT_UNLOCK_CHECK_EXCEPTION(env);
}
sysColors = (*env)->FindClass (env, "java/awt/SystemColor");
CHECK_NULL(sysColors);
--- a/jdk/src/java.desktop/unix/native/common/sun/awt/awt.h Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/unix/native/common/sun/awt/awt.h Wed Jul 05 19:59:54 2017 +0200
@@ -75,6 +75,12 @@
AWT_NOFLUSH_UNLOCK(); \
} while (0)
+#define AWT_UNLOCK_CHECK_EXCEPTION(env) \
+ do { \
+ AWT_UNLOCK(); \
+ JNU_CHECK_EXCEPTION(env); \
+ } while (0)
+
#define AWT_LOCK_IMPL() \
(*env)->CallStaticVoidMethod(env, tkClass, awtLockMID)
--- a/jdk/src/java.desktop/unix/native/libawt_xawt/sun/awt/awt_GraphicsEnv.c Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/unix/native/libawt_xawt/sun/awt/awt_GraphicsEnv.c Wed Jul 05 19:59:54 2017 +0200
@@ -1348,7 +1348,9 @@
}
/* Make Color Model object for this GraphicsConfiguration */
- colorModel = awtJNI_GetColorModel (env, adata);
+ colorModel = (*env)->ExceptionCheck(env)
+ ? NULL : awtJNI_GetColorModel (env, adata);
+
AWT_UNLOCK ();
return colorModel;
@@ -2052,7 +2054,7 @@
AWT_FLUSH_UNLOCK();
- if (!success) {
+ if (!success && !(*env)->ExceptionCheck(env)) {
JNU_ThrowInternalError(env, "Could not set display mode");
}
#endif /* !HEADLESS */
--- a/jdk/src/java.desktop/unix/native/libawt_xawt/sun/awt/sun_awt_X11_GtkFileDialogPeer.c Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/unix/native/libawt_xawt/sun/awt/sun_awt_X11_GtkFileDialogPeer.c Wed Jul 05 19:59:54 2017 +0200
@@ -246,8 +246,14 @@
}
str = (*env)->NewStringUTF(env, entry);
- if (str && !(*env)->ExceptionCheck(env)) {
+ if((*env)->ExceptionCheck(env)){
+ break;
+ }
+ if (str) {
(*env)->SetObjectArrayElement(env, array, i, str);
+ if((*env)->ExceptionCheck(env)){
+ break;
+ }
}
}
--- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WLightweightFramePeer.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WLightweightFramePeer.java Wed Jul 05 19:59:54 2017 +0200
@@ -27,6 +27,7 @@
import java.awt.Component;
import java.awt.Graphics;
+import java.awt.dnd.DropTarget;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
@@ -94,4 +95,14 @@
public boolean isLightweightFramePeer() {
return true;
}
+
+ @Override
+ public void addDropTarget(DropTarget dt) {
+ getLwTarget().addDropTarget(dt);
+ }
+
+ @Override
+ public void removeDropTarget(DropTarget dt) {
+ getLwTarget().removeDropTarget(dt);
+ }
}
--- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java Wed Jul 05 19:59:54 2017 +0200
@@ -844,6 +844,11 @@
@Override
public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException {
+ final LightweightFrame f = SunToolkit.getLightweightFrame(dge.getComponent());
+ if (f != null) {
+ return f.createDragSourceContextPeer(dge);
+ }
+
return WDragSourceContextPeer.createDragSourceContextPeer(dge);
}
@@ -854,6 +859,11 @@
DragSource ds, Component c, int srcActions,
DragGestureListener dgl)
{
+ final LightweightFrame f = SunToolkit.getLightweightFrame(c);
+ if (f != null) {
+ return f.createDragGestureRecognizer(abstractRecognizerClass, ds, c, srcActions, dgl);
+ }
+
if (MouseDragGestureRecognizer.class.equals(abstractRecognizerClass))
return (T)new WMouseDragGestureRecognizer(ds, c, srcActions, dgl);
else
--- a/jdk/src/java.desktop/windows/native/libawt/sun/windows/WPrinterJob.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/windows/native/libawt/sun/windows/WPrinterJob.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2014, 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
@@ -995,14 +995,7 @@
if (type == GETJOBCOUNT) {
ret = pPrinterInfo->cJobs;
} else if (type == ACCEPTJOB) {
- if (pPrinterInfo->Status &
- (PRINTER_STATUS_ERROR |
- PRINTER_STATUS_NOT_AVAILABLE |
- PRINTER_STATUS_NO_TONER |
- PRINTER_STATUS_OUT_OF_MEMORY |
- PRINTER_STATUS_OFFLINE |
- PRINTER_STATUS_USER_INTERVENTION |
- PRINTER_STATUS_DOOR_OPEN)) {
+ if (pPrinterInfo->Status & PRINTER_STATUS_PENDING_DELETION) {
ret = 0;
}
else {
--- a/jdk/src/java.desktop/windows/native/libawt/sun/windows/awt_InputMethod.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/windows/native/libawt/sun/windows/awt_InputMethod.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -482,6 +482,7 @@
for (current = 0; current < destIndex; current++) {
if (strcmp(javaLocaleNames[current], srcLocaleName) == 0) {
// duplicated. ignore this HKL
+ free((void *)srcLocaleName);
break;
}
}
--- a/jdk/src/java.desktop/windows/native/libawt/sun/windows/awt_Win32GraphicsDevice.cpp Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/java.desktop/windows/native/libawt/sun/windows/awt_Win32GraphicsDevice.cpp Wed Jul 05 19:59:54 2017 +0200
@@ -835,13 +835,17 @@
TRY;
/* class ids */
- AwtWin32GraphicsDevice::indexCMClass =
- (jclass)env->NewGlobalRef(env->FindClass("java/awt/image/IndexColorModel"));
+ jclass iCMClass = env->FindClass("java/awt/image/IndexColorModel");
+ CHECK_NULL(iCMClass);
+ AwtWin32GraphicsDevice::indexCMClass = (jclass) env->NewGlobalRef(iCMClass);
+ env->DeleteLocalRef(iCMClass);
DASSERT(AwtWin32GraphicsDevice::indexCMClass);
CHECK_NULL(AwtWin32GraphicsDevice::indexCMClass);
- AwtWin32GraphicsDevice::wToolkitClass =
- (jclass)env->NewGlobalRef(env->FindClass("sun/awt/windows/WToolkit"));
+ jclass wTClass = env->FindClass("sun/awt/windows/WToolkit");
+ CHECK_NULL(wTClass);
+ AwtWin32GraphicsDevice::wToolkitClass = (jclass)env->NewGlobalRef(wTClass);
+ env->DeleteLocalRef(wTClass);
DASSERT(AwtWin32GraphicsDevice::wToolkitClass);
CHECK_NULL(AwtWin32GraphicsDevice::wToolkitClass);
--- a/jdk/src/jdk.jconsole/share/classes/sun/tools/jconsole/inspector/TableSorter.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/jdk.jconsole/share/classes/sun/tools/jconsole/inspector/TableSorter.java Wed Jul 05 19:59:54 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2014, 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
@@ -146,7 +146,7 @@
// update row heights in XMBeanAttributes (required by expandable cells)
if (attrs != null) {
for (int i = 0; i < getRowCount(); i++) {
- Vector<?> data = (Vector) dataVector.elementAt(i);
+ Vector<?> data = dataVector.elementAt(i);
attrs.updateRowHeight(data.elementAt(1), i);
}
}
@@ -217,17 +217,17 @@
}
}
- private Vector<Object> getRow(int row) {
+ private Vector<?> getRow(int row) {
return dataVector.elementAt(row);
}
@SuppressWarnings("unchecked")
- private void setRow(Vector<Object> data, int row) {
+ private void setRow(Vector<?> data, int row) {
dataVector.setElementAt(data,row);
}
private void swap(int i, int j, int column) {
- Vector<Object> data = getRow(i);
+ Vector<?> data = getRow(i);
setRow(getRow(j),i);
setRow(data,j);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.localedata/META-INF/cldrdata-services/sun.util.locale.provider.LocaleDataMetaInfo Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,1 @@
+sun.util.cldr.CLDRLocaleDataMetaInfo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.localedata/META-INF/localedata-services/sun.util.locale.provider.LocaleDataMetaInfo Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,1 @@
+sun.util.resources.provider.NonEnLocaleDataMetaInfo
--- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/lt/CurrencyNames_lt_LT.properties Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/lt/CurrencyNames_lt_LT.properties Wed Jul 05 19:59:54 2017 +0200
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -35,4 +35,5 @@
# This notice and attribution to Taligent may not be removed.
# Taligent is a registered trademark of Taligent, Inc.
+EUR=\u20AC
LTL=Lt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Frame/MiscUndecorated/ActiveAWTWindowTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 1999, 2014, 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 To check proper WINDOW_EVENTS are triggered when Frame gains or losses the focus
+* @author Jitender(jitender.singh@eng.sun.com) area=AWT
+* @author yan
+* @library ../../../../lib/testlibrary
+* @build ExtendedRobot
+* @run main ActiveAWTWindowTest
+*/
+
+import java.awt.*;
+import java.awt.event.*;
+
+public class ActiveAWTWindowTest {
+
+ private Frame frame, frame2;
+ private Button button, button2;
+ private TextField textField, textField2;
+ private int eventType, eventType1;
+ private ExtendedRobot robot;
+ private Object lock1 = new Object();
+ private Object lock2 = new Object();
+ private Object lock3 = new Object();
+ private boolean passed = true;
+ private int delay = 150;
+
+ public static void main(String[] args) {
+ ActiveAWTWindowTest test = new ActiveAWTWindowTest();
+ test.doTest();
+ }
+
+ public ActiveAWTWindowTest() {
+ try{
+ EventQueue.invokeAndWait( () -> {
+ initializeGUI();
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Interrupted or unexpected Exception occured");
+ }
+ }
+
+ private void initializeGUI() {
+ frame = new Frame();
+ frame.setLayout(new FlowLayout());
+
+ frame.setLocation(5, 20);
+ frame.setSize(200, 200);
+ frame.setUndecorated(true);
+ frame.addWindowFocusListener(new WindowFocusListener() {
+ public void windowGainedFocus(WindowEvent event) {
+ System.out.println("Frame Focus gained");
+ synchronized (lock3) {
+ try {
+ lock3.notifyAll();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ public void windowLostFocus(WindowEvent event) {
+ System.out.println("Frame Focus lost");
+ }
+ });
+ frame.addWindowListener(new WindowAdapter() {
+ public void windowActivated(WindowEvent e) {
+ eventType = WindowEvent.WINDOW_ACTIVATED;
+ System.out.println("Undecorated Frame is activated\n");
+ synchronized (lock1) {
+ try {
+ lock1.notifyAll();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ public void windowDeactivated(WindowEvent e) {
+ eventType = WindowEvent.WINDOW_DEACTIVATED;
+ System.out.println("Undecorated Frame got Deactivated\n");
+ synchronized (lock2) {
+ try {
+ lock2.notifyAll();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+ });
+ textField = new TextField("TextField");
+ button = new Button("Click me");
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ textField.setText("Focus gained");
+ }
+ });
+
+ frame.setBackground(Color.green);
+ frame.add(button);
+ frame.add(textField);
+ frame.setVisible(true);
+
+ frame2 = new Frame();
+ frame2.setLayout(new FlowLayout());
+ frame2.setLocation(5, 250);
+ frame2.setSize(200, 200);
+ frame2.setBackground(Color.green);
+ button2 = new Button("Click me");
+ textField2 = new TextField("TextField");
+ button2.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ textField2.setText("Got the focus");
+ }
+ });
+
+ frame2.add(button2, BorderLayout.SOUTH);
+ frame2.add(textField2, BorderLayout.NORTH);
+ frame2.setVisible(true);
+
+ frame.toFront();
+ }
+
+ public void doTest() {
+ try {
+ robot = new ExtendedRobot();
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Cannot create robot");
+ }
+
+ robot.waitForIdle(5*delay);
+ robot.mouseMove(button.getLocationOnScreen().x + button.getSize().width / 2,
+ button.getLocationOnScreen().y + button.getSize().height / 2);
+ robot.waitForIdle(delay);
+ robot.mousePress(InputEvent.BUTTON1_MASK);
+ robot.waitForIdle(delay);
+ robot.mouseRelease(InputEvent.BUTTON1_MASK);
+
+ if (eventType != WindowEvent.WINDOW_ACTIVATED) {
+ synchronized (lock1) {
+ try {
+ lock1.wait(delay * 10);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ if (eventType != WindowEvent.WINDOW_ACTIVATED) {
+ passed = false;
+ System.err.println("WINDOW_ACTIVATED event did not occur when the " +
+ "undecorated frame is activated!");
+ }
+
+ eventType1 = -1;
+ eventType = -1;
+
+ robot.mouseMove(button2.getLocationOnScreen().x + button2.getSize().width / 2,
+ button2.getLocationOnScreen().y + button2.getSize().height / 2);
+ robot.waitForIdle(delay);
+ robot.mousePress(InputEvent.BUTTON1_MASK);
+ robot.waitForIdle(delay);
+ robot.mouseRelease(InputEvent.BUTTON1_MASK);
+
+ if (eventType != WindowEvent.WINDOW_DEACTIVATED) {
+ synchronized (lock2) {
+ try {
+ lock2.wait(delay * 10);
+ } catch (Exception e) {
+ }
+ }
+ }
+ if (eventType != WindowEvent.WINDOW_DEACTIVATED) {
+ passed = false;
+ System.err.println("FAIL: WINDOW_DEACTIVATED event did not occur for the " +
+ "undecorated frame when another frame gains focus!");
+ }
+ if (frame.hasFocus()) {
+ passed = false;
+ System.err.println("FAIL: The undecorated frame has focus even when " +
+ "another frame is clicked!");
+ }
+
+ if (!passed) {
+ //captureScreenAndSave();
+ System.err.println("Test failed!");
+ throw new RuntimeException("Test failed.");
+ } else {
+ System.out.println("Test passed");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Frame/MiscUndecorated/ActiveSwingWindowTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 1999, 2014, 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 To check proper WINDOW_EVENTS are triggered when JFrame gains or losses the focus
+* @author Jitender(jitender.singh@eng.sun.com) area=AWT
+* @author yan
+* @library ../../../../lib/testlibrary
+* @build ExtendedRobot
+* @run main ActiveSwingWindowTest
+*/
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.JFrame;
+import javax.swing.JTextField;
+import javax.swing.JButton;
+
+
+public class ActiveSwingWindowTest {
+
+ private JFrame frame, frame2;
+ private JButton button, button2;
+ private JTextField textField, textField2;
+ private int eventType, eventType1;
+ private ExtendedRobot robot;
+ private Object lock1 = new Object();
+ private Object lock2 = new Object();
+ private Object lock3 = new Object();
+ private boolean passed = true;
+ private int delay = 150;
+
+ public static void main(String[] args) {
+ ActiveSwingWindowTest test = new ActiveSwingWindowTest();
+ test.doTest();
+ }
+
+ public ActiveSwingWindowTest() {
+ try{
+ EventQueue.invokeAndWait( () -> {
+ initializeGUI();
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Interrupted or unexpected Exception occured");
+ }
+ }
+
+ private void initializeGUI() {
+ frame = new JFrame();
+ frame.setLayout(new FlowLayout());
+
+ frame.setLocation(5, 20);
+ frame.setSize(200, 200);
+ frame.setUndecorated(true);
+ frame.addWindowFocusListener(new WindowFocusListener() {
+ public void windowGainedFocus(WindowEvent event) {
+ System.out.println("Frame Focus gained");
+ synchronized (lock3) {
+ try {
+ lock3.notifyAll();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ public void windowLostFocus(WindowEvent event) {
+ System.out.println("Frame Focus lost");
+ }
+ });
+ frame.addWindowListener(new WindowAdapter() {
+ public void windowActivated(WindowEvent e) {
+ eventType = WindowEvent.WINDOW_ACTIVATED;
+ System.out.println("Undecorated Frame is activated\n");
+ synchronized (lock1) {
+ try {
+ lock1.notifyAll();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ public void windowDeactivated(WindowEvent e) {
+ eventType = WindowEvent.WINDOW_DEACTIVATED;
+ System.out.println("Undecorated Frame got Deactivated\n");
+ synchronized (lock2) {
+ try {
+ lock2.notifyAll();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+ });
+ textField = new JTextField("TextField");
+ button = new JButton("Click me");
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ textField.setText("Focus gained");
+ }
+ });
+
+ frame.setBackground(Color.green);
+ frame.add(button);
+ frame.add(textField);
+ frame.setVisible(true);
+
+ frame2 = new JFrame();
+ frame2.setLayout(new FlowLayout());
+ frame2.setLocation(5, 250);
+ frame2.setSize(200, 200);
+ frame2.setBackground(Color.green);
+ button2 = new JButton("Click me");
+ textField2 = new JTextField("TextField");
+ button2.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ textField2.setText("Got the focus");
+ }
+ });
+
+ frame2.add(button2, BorderLayout.SOUTH);
+ frame2.add(textField2, BorderLayout.NORTH);
+ frame2.setVisible(true);
+
+ frame.toFront();
+ }
+
+ public void doTest() {
+ try {
+ robot = new ExtendedRobot();
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Cannot create robot");
+ }
+
+ robot.waitForIdle(5*delay);
+ robot.mouseMove(button.getLocationOnScreen().x + button.getSize().width / 2,
+ button.getLocationOnScreen().y + button.getSize().height / 2);
+ robot.waitForIdle(delay);
+ robot.mousePress(InputEvent.BUTTON1_MASK);
+ robot.waitForIdle(delay);
+ robot.mouseRelease(InputEvent.BUTTON1_MASK);
+
+ if (eventType != WindowEvent.WINDOW_ACTIVATED) {
+ synchronized (lock1) {
+ try {
+ lock1.wait(delay * 10);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ if (eventType != WindowEvent.WINDOW_ACTIVATED) {
+ passed = false;
+ System.err.println("WINDOW_ACTIVATED event did not occur when the " +
+ "undecorated frame is activated!");
+ }
+
+ eventType1 = -1;
+ eventType = -1;
+
+ robot.mouseMove(button2.getLocationOnScreen().x + button2.getSize().width / 2,
+ button2.getLocationOnScreen().y + button2.getSize().height / 2);
+ robot.waitForIdle(delay);
+ robot.mousePress(InputEvent.BUTTON1_MASK);
+ robot.waitForIdle(delay);
+ robot.mouseRelease(InputEvent.BUTTON1_MASK);
+
+ if (eventType != WindowEvent.WINDOW_DEACTIVATED) {
+ synchronized (lock2) {
+ try {
+ lock2.wait(delay * 10);
+ } catch (Exception e) {
+ }
+ }
+ }
+ if (eventType != WindowEvent.WINDOW_DEACTIVATED) {
+ passed = false;
+ System.err.println("FAIL: WINDOW_DEACTIVATED event did not occur for the " +
+ "undecorated frame when another frame gains focus!");
+ }
+ if (frame.hasFocus()) {
+ passed = false;
+ System.err.println("FAIL: The undecorated frame has focus even when " +
+ "another frame is clicked!");
+ }
+
+ if (!passed) {
+ //captureScreenAndSave();
+ System.err.println("Test failed!");
+ throw new RuntimeException("Test failed.");
+ } else {
+ System.out.println("Test passed");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Frame/MiscUndecorated/FrameCloseTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 1999, 2014, 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 To make sure Undecorated Frame triggers correct windows events while closing
+* @author Jitender(jitender.singh@eng.sun.com) area=AWT*
+* @author yan
+* @library ../../../../lib/testlibrary
+* @build ExtendedRobot
+* @run main FrameCloseTest
+*/
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.JFrame;
+import javax.swing.JButton;
+
+public class FrameCloseTest {
+ private static int delay = 150;
+
+ private Frame frame, frame2;
+ private Component button, dummyButton;
+ private int eventType, eventType1, eventType2;
+ private ExtendedRobot robot;
+ private Object lock1 = new Object();
+ private Object lock2 = new Object();
+ private Object lock3 = new Object();
+ private Object lock4 = new Object();
+ private boolean passed = true;
+
+ public static void main(String[] args) {
+ FrameCloseTest test = new FrameCloseTest();
+ test.doTest(false);
+ test.doTest(true);
+ }
+
+ private void initializeGUI(boolean swingFrame) {
+ frame = swingFrame? new Frame() : new JFrame();
+ frame.setLayout(new FlowLayout());
+
+ frame.setLocation(5, 20);
+ frame.setSize(200, 200);
+ frame.setUndecorated(true);
+ frame.addWindowFocusListener(new WindowFocusListener() {
+ public void windowGainedFocus(WindowEvent event) {
+ System.out.println("Frame Focus gained");
+ synchronized (lock4) {
+ try {
+ lock4.notifyAll();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ public void windowLostFocus(WindowEvent event) {
+ System.out.println("Frame Focus lost");
+ }
+ });
+ frame.addWindowListener(new WindowAdapter() {
+ public void windowActivated(WindowEvent e) {
+ eventType = WindowEvent.WINDOW_ACTIVATED;
+ System.out.println("Undecorated Frame is activated");
+ synchronized (lock1) {
+ try {
+ lock1.notifyAll();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ public void windowDeactivated(WindowEvent e) {
+ eventType1 = WindowEvent.WINDOW_DEACTIVATED;
+ System.out.println("Undecorated Frame got Deactivated");
+ synchronized (lock2) {
+ try {
+ lock2.notifyAll();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ public void windowClosed(WindowEvent e) {
+ eventType2 = WindowEvent.WINDOW_CLOSED;
+ System.out.println("Undecorated Frame got closed");
+ synchronized (lock3) {
+ try {
+ lock3.notifyAll();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+ });
+ dummyButton = swingFrame? new JButton("Click me") : new Button("Click me");
+
+ frame.setBackground(Color.green);
+ frame.add((button = createButton(swingFrame, "Close me")));
+ frame.add(dummyButton);
+ frame.setVisible(true);
+ frame.toFront();
+ }
+ private Component createButton(boolean swingControl, String txt) {
+ if(swingControl) {
+ JButton jbtn = new JButton(txt);
+ jbtn.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ frame.dispose();
+ }
+ });
+ return jbtn;
+ }else {
+ Button btn = new Button(txt);
+ btn.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ frame.dispose();
+ }
+ });
+ return btn;
+ }
+ }
+
+ public void doTest(boolean swingControl) {
+ try {
+ Toolkit.getDefaultToolkit().getSystemEventQueue().invokeAndWait(new Runnable() {
+ public void run() {
+ initializeGUI(swingControl);
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Interrupted or unexpected Exception occured");
+ }
+ try {
+ robot = new ExtendedRobot();
+ robot.waitForIdle(1000);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Cannot create robot");
+ }
+
+ robot.mouseMove(dummyButton.getLocationOnScreen().x + dummyButton.getSize().width / 2,
+ dummyButton.getLocationOnScreen().y + dummyButton.getSize().height / 2);
+ robot.waitForIdle(delay);
+ robot.mousePress(InputEvent.BUTTON1_MASK);
+ robot.waitForIdle(delay);
+ robot.mouseRelease(InputEvent.BUTTON1_MASK);
+ robot.waitForIdle(delay);
+
+ eventType1 = -1;
+ eventType = -1;
+ eventType2 = -1;
+
+ robot.mouseMove(button.getLocationOnScreen().x + button.getSize().width / 2,
+ button.getLocationOnScreen().y + button.getSize().height / 2);
+ robot.waitForIdle(delay);
+ robot.mousePress(InputEvent.BUTTON1_MASK);
+ robot.waitForIdle(delay);
+ robot.mouseRelease(InputEvent.BUTTON1_MASK);
+ robot.waitForIdle(delay * 10);
+
+ if (eventType2 != WindowEvent.WINDOW_CLOSED) {
+ synchronized (lock3) {
+ try {
+ lock3.wait(delay * 10);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ if (eventType2 != WindowEvent.WINDOW_CLOSED) {
+ passed = false;
+ System.err.println("WINDOW_CLOSED event did not occur when the " +
+ "undecorated frame is closed!");
+ }
+ if (eventType == WindowEvent.WINDOW_ACTIVATED) {
+ passed = false;
+ System.err.println("WINDOW_ACTIVATED event occured when the " +
+ "undecorated frame is closed!");
+ }
+
+ if (!passed) {
+ System.err.println("Test failed!");
+ throw new RuntimeException("Test failed");
+ } else {
+ System.out.println("Test passed");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Frame/MiscUndecorated/RepaintTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 1999, 2014, 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 Make sure that on changing state of Undecorated Frame,
+* all the components on it are repainted correctly
+* @author Jitender(jitender.singh@eng.sun.com) area=AWT
+* @author yan
+* @library ../../../../lib/testlibrary
+* @build ExtendedRobot
+* @run main RepaintTest
+*/
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.JFrame;
+import javax.swing.JButton;
+import javax.swing.JTextField;
+import javax.swing.JPanel;
+import java.io.*;
+import java.awt.image.*;
+
+public class RepaintTest {
+ private static int delay = 150;
+
+ private Frame frame;
+ private Container panel1, panel2;
+ private Component button;
+ private Component textField;
+ private ExtendedRobot robot;
+ private Object buttonLock = new Object();
+ private boolean passed = true;
+ private boolean buttonClicked = false;
+ private int MAX_TOLERANCE_LEVEL = 10;
+
+ public static void main(String[] args) {
+ RepaintTest test = new RepaintTest();
+ test.doTest(false);
+ try {
+ Toolkit.getDefaultToolkit().getSystemEventQueue().invokeAndWait(new Runnable() {
+ public void run() {
+ test.frame.dispose();
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Unexpected Exception occured");
+ }
+ test.doTest(true);
+ try {
+ Toolkit.getDefaultToolkit().getSystemEventQueue().invokeAndWait(new Runnable() {
+ public void run() {
+ test.frame.dispose();
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Unexpected Exception occured");
+ }
+ }
+
+ /**
+ * Do screen capture and save it as image
+ */
+ private static void captureScreenAndSave() {
+
+ try {
+ Robot robot = new Robot();
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ Rectangle rectangle = new Rectangle(0, 0, screenSize.width, screenSize.height);
+ System.out.println("About to screen capture - " + rectangle);
+ BufferedImage image = robot.createScreenCapture(rectangle);
+ javax.imageio.ImageIO.write(image, "jpg", new File("ScreenImage.jpg"));
+ robot.delay(3000);
+ } catch (Throwable t) {
+ System.out.println("WARNING: Exception thrown while screen capture!");
+ t.printStackTrace();
+ }
+ }
+
+ private void initializeGUI(boolean swingControl) {
+ frame = swingControl ? new JFrame() : new Frame();
+ frame.setLayout(new BorderLayout());
+
+ frame.setSize(300, 300);
+ frame.setUndecorated(true);
+
+ button = createButton(swingControl, (swingControl ? "Swing Button" : "AWT Button"));
+ textField = swingControl ? new JTextField("TextField") : new TextField("TextField");
+ panel1 = swingControl ? new JPanel() : new Panel();
+ panel2 = swingControl ? new JPanel() : new Panel();
+ panel1.add(button);
+ panel2.add(textField);
+ frame.add(panel2, BorderLayout.SOUTH);
+ frame.add(panel1, BorderLayout.NORTH);
+
+ frame.setBackground(Color.green);
+ frame.setVisible(true);
+ frame.toFront();
+ }
+ private Component createButton(boolean swingControl, String txt) {
+ if(swingControl) {
+ JButton jbtn = new JButton(txt);
+ jbtn.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ buttonClicked = true;
+ synchronized (buttonLock) {
+ try {
+ buttonLock.notifyAll();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+ });
+ return jbtn;
+ }else {
+ Button btn = new Button(txt);
+ btn.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ buttonClicked = true;
+ synchronized (buttonLock) {
+ try {
+ buttonLock.notifyAll();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+ });
+ return btn;
+ }
+ }
+
+ public void doTest(boolean swingControl) {
+ try {
+ Toolkit.getDefaultToolkit().getSystemEventQueue().invokeAndWait(new Runnable() {
+ public void run() {
+ initializeGUI(swingControl);
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Interrupted or unexpected Exception occured");
+ }
+ try {
+ robot = new ExtendedRobot();
+ robot.waitForIdle(1000);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Cannot create robot");
+ }
+
+ robot.mouseMove(button.getLocationOnScreen().x + button.getSize().width / 2,
+ button.getLocationOnScreen().y + button.getSize().height / 2);
+ robot.waitForIdle(delay);
+ robot.mousePress(InputEvent.BUTTON1_MASK);
+ robot.waitForIdle(delay);
+ robot.mouseRelease(InputEvent.BUTTON1_MASK);
+
+ if (! buttonClicked) {
+ synchronized (buttonLock) {
+ try {
+ buttonLock.wait(delay * 10);
+ } catch (Exception e) {
+ }
+ }
+ }
+ if (! buttonClicked) {
+ passed = false;
+ System.err.println("ActionEvent not triggered when " +
+ "button is clicked!");
+ throw new RuntimeException("ActionEvent not triggered");
+ }
+
+ robot.waitForIdle(delay * 5); // Need to wait until look of the button
+ // returns to normal undepressed
+ passed = paintAndRepaint(button, (swingControl? "J": "")+"Button");
+ if( !paintAndRepaint(button, (swingControl? "J": "")+"TextField") ) {
+ passed = false;
+ }
+ if(!passed) {
+ throw new RuntimeException("Test failed");
+ }
+ }
+ private boolean paintAndRepaint(Component comp, String prefix) {
+ //Capture the component & compare it's dimensions
+ //before iconifying & after frame comes back from
+ //iconified to normal state
+ System.out.println("paintAndRepaint "+prefix);
+ Point p = comp.getLocationOnScreen();
+ Rectangle bRect = new Rectangle((int)p.getX(), (int)p.getY(),
+ comp.getWidth(), comp.getHeight());
+ BufferedImage capturedImage = robot.createScreenCapture(bRect);
+
+ try {
+ Toolkit.getDefaultToolkit().getSystemEventQueue().invokeAndWait(new Runnable() {
+ public void run() {
+ frame.setExtendedState(Frame.ICONIFIED);
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Exception while setting extended state ICONIFIED");
+ }
+ robot.waitForIdle(delay * 5);
+ try {
+ Toolkit.getDefaultToolkit().getSystemEventQueue().invokeAndWait(new Runnable() {
+ public void run() {
+ frame.setExtendedState(Frame.NORMAL);
+ frame.toFront();
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Exception while setting extended state NORMAL");
+ }
+ robot.waitForIdle(delay * 5);
+
+ if (! p.equals(comp.getLocationOnScreen())) {
+ passed = false;
+ System.err.println("FAIL: Frame or component did not get positioned in the same place");
+ }
+
+ p = comp.getLocationOnScreen();
+ bRect = new Rectangle((int)p.getX(), (int)p.getY(),
+ comp.getWidth(), comp.getHeight());
+ BufferedImage capturedImage2 = robot.createScreenCapture(bRect);
+
+ if (! compareImages(capturedImage, capturedImage2)) {
+ passed = false;
+ try {
+ javax.imageio.ImageIO.write(capturedImage, "jpg", new File(
+ prefix+"BeforeMinimize.jpg"));
+ javax.imageio.ImageIO.write(capturedImage2, "jpg", new File(
+ prefix+"AfterMinimize.jpg"));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ System.err.println("FAIL: The frame or component did not get repainted correctly");
+ }
+ return passed;
+ }
+
+ //method for comparing two images
+ public boolean compareImages(BufferedImage capturedImg, BufferedImage realImg) {
+ int capturedPixels[], realPixels[];
+ int imgWidth, imgHeight;
+ boolean comparison = true;
+ int toleranceLevel = 0;
+
+ imgWidth = capturedImg.getWidth(null);
+ imgHeight = capturedImg.getHeight(null);
+ capturedPixels = new int[imgWidth * imgHeight];
+ realPixels = new int[imgWidth * imgHeight];
+
+ try {
+ PixelGrabber pgCapturedImg = new PixelGrabber(capturedImg, 0, 0,
+ imgWidth, imgHeight, capturedPixels, 0, imgWidth);
+ pgCapturedImg.grabPixels();
+
+ PixelGrabber pgRealImg = new PixelGrabber(realImg, 0, 0,
+ imgWidth, imgHeight, realPixels, 0, imgWidth);
+ pgRealImg.grabPixels();
+
+ for(int i=0; i<(imgWidth * imgHeight); i++) {
+ if(capturedPixels[i] != realPixels[i]) {
+ toleranceLevel++;
+ }
+ }
+
+ if (toleranceLevel > MAX_TOLERANCE_LEVEL) {
+ comparison = false;
+ }
+ } catch(Exception ie) {
+ ie.printStackTrace();
+ comparison = false;
+ }
+ return comparison;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Frame/MiscUndecorated/UndecoratedInitiallyIconified.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2002, 2014, 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.awt.Frame;
+import java.awt.Toolkit;
+import javax.swing.JFrame;
+import java.awt.EventQueue;
+import java.awt.FlowLayout;
+/*
+ * @test
+ * @bug 4464710 7102299
+ * @summary Recurring bug is, an undecorated JFrame cannot be set iconified
+ * before setVisible(true)
+ *
+ * @run main UndecoratedInitiallyIconified
+ */
+
+
+public class UndecoratedInitiallyIconified {
+ private static JFrame frame;
+ public static void main(String args[]) throws Exception {
+ if (!Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.ICONIFIED)) {
+ return;
+ }
+ EventQueue.invokeAndWait( () -> {
+ frame = new JFrame("Test Frame");
+ frame.setLayout(new FlowLayout());
+ frame.setBounds(50,50,300,300);
+ frame.setUndecorated(true);
+ frame.setExtendedState(Frame.ICONIFIED);
+ if(frame.getExtendedState() != Frame.ICONIFIED) {
+ throw new RuntimeException("getExtendedState is not Frame.ICONIFIED as expected");
+ }
+ });
+ }
+}
--- a/jdk/test/java/awt/Mixing/AWT_Mixing/Util.java Thu Sep 04 13:26:26 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,601 +0,0 @@
-/*
- * Copyright (c) 2014, 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.awt.Component;
-import java.awt.Frame;
-import java.awt.Dialog;
-import java.awt.Window;
-import java.awt.Button;
-import java.awt.Point;
-import java.awt.Dimension;
-import java.awt.Rectangle;
-import java.awt.Robot;
-import java.awt.Toolkit;
-import java.awt.IllegalComponentStateException;
-import java.awt.AWTException;
-import java.awt.AWTEvent;
-
-import java.awt.event.InputEvent;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.awt.event.ActionEvent;
-import java.awt.event.FocusEvent;
-import java.awt.event.WindowListener;
-import java.awt.event.WindowFocusListener;
-import java.awt.event.FocusListener;
-import java.awt.event.ActionListener;
-
-import java.awt.peer.FramePeer;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import java.security.PrivilegedAction;
-import java.security.AccessController;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * <p>This class contains utilities useful for regression testing.
- * <p>When using jtreg you would include this class into the build
- * list via something like:
- * <pre>
- &library ../../../../share/lib/AWT_Mixing/src/regtesthelpers/
- &build Util
- &run main YourTest
- </pre>
- * Note that if you are about to create a test based on
- * Applet-template, then put those lines into html-file, not in java-file.
- * <p> And put an
- * import regtesthelpers.Util;
- * into the java source of test.
-*/
-public final class Util {
- private Util() {} // this is a helper class with static methods :)
-
- /*
- * @throws RuntimeException when creation failed
- */
- public static Robot createRobot() {
- try {
- return new Robot();
- } catch (AWTException e) {
- throw new RuntimeException("Error: unable to create robot", e);
- }
- }
-
- public static Frame createEmbeddedFrame(final Frame embedder)
- throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException,
- InstantiationException, InvocationTargetException
- {
- Toolkit tk = Toolkit.getDefaultToolkit();
- FramePeer frame_peer = (FramePeer) embedder.getPeer();
- System.out.println("frame's peer = " + frame_peer);
- if ("sun.awt.windows.WToolkit".equals(tk.getClass().getName())) {
- Class comp_peer_class =
- Class.forName("sun.awt.windows.WComponentPeer");
- System.out.println("comp peer class = " + comp_peer_class);
- Field hwnd_field = comp_peer_class.getDeclaredField("hwnd");
- hwnd_field.setAccessible(true);
- System.out.println("hwnd_field =" + hwnd_field);
- long hwnd = hwnd_field.getLong(frame_peer);
- System.out.println("hwnd = " + hwnd);
-
- Class clazz = Class.forName("sun.awt.windows.WEmbeddedFrame");
- Constructor constructor = clazz.getConstructor (new Class [] {Long.TYPE});
- return (Frame) constructor.newInstance (new Object[] {hwnd});
- } else if ("sun.awt.X11.XToolkit".equals(tk.getClass().getName())) {
- Class x_base_window_class = Class.forName("sun.awt.X11.XBaseWindow");
- System.out.println("x_base_window_class = " + x_base_window_class);
- Method get_window = x_base_window_class.getMethod("getWindow", new Class[0]);
- System.out.println("get_window = " + get_window);
- long window = (Long) get_window.invoke(frame_peer, new Object[0]);
- System.out.println("window = " + window);
- Class clazz = Class.forName("sun.awt.X11.XEmbeddedFrame");
- Constructor constructor = clazz.getConstructor (new Class [] {Long.TYPE, Boolean.TYPE});
- return (Frame) constructor.newInstance (new Object[] {window, true});
- }
-
- throw new RuntimeException("Unexpected toolkit - " + tk);
- }
-
- /**
- * Makes the window visible and waits until it's shown.
- */
- public static void showWindowWait(Window win) {
- win.setVisible(true);
- waitTillShown(win);
- }
-
- /**
- * Moves mouse pointer in the center of given {@code comp} component
- * using {@code robot} parameter.
- */
- public static void pointOnComp(final Component comp, final Robot robot) {
- Rectangle bounds = new Rectangle(comp.getLocationOnScreen(), comp.getSize());
- robot.mouseMove(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);
- }
-
- /**
- * Moves mouse pointer in the center of a given {@code comp} component
- * and performs a left mouse button click using the {@code robot} parameter
- * with the {@code delay} delay between press and release.
- */
- public static void clickOnComp(final Component comp, final Robot robot, int delay) {
- pointOnComp(comp, robot);
- robot.delay(delay);
- robot.mousePress(InputEvent.BUTTON1_MASK);
- robot.delay(delay);
- robot.mouseRelease(InputEvent.BUTTON1_MASK);
- }
-
- /**
- * Moves mouse pointer in the center of a given {@code comp} component
- * and performs a left mouse button click using the {@code robot} parameter
- * with the default delay between press and release.
- */
- public static void clickOnComp(final Component comp, final Robot robot) {
- clickOnComp(comp, robot, 50);
- }
-
- /*
- * Clicks on a title of Frame/Dialog.
- * WARNING: it may fail on some platforms when the window is not wide enough.
- */
- public static void clickOnTitle(final Window decoratedWindow, final Robot robot) {
- Point p = decoratedWindow.getLocationOnScreen();
- Dimension d = decoratedWindow.getSize();
-
- if (decoratedWindow instanceof Frame || decoratedWindow instanceof Dialog) {
- robot.mouseMove(p.x + (int)(d.getWidth()/2), p.y + (int)decoratedWindow.getInsets().top/2);
- robot.delay(50);
- robot.mousePress(InputEvent.BUTTON1_MASK);
- robot.delay(50);
- robot.mouseRelease(InputEvent.BUTTON1_MASK);
- }
- }
-
- public static void waitForIdle(final Robot robot) {
- // we do not use robot for now, use SunToolkit.realSync() instead
- ((sun.awt.SunToolkit)Toolkit.getDefaultToolkit()).realSync();
- }
-
- public static Field getField(final Class klass, final String fieldName) {
- return AccessController.doPrivileged(new PrivilegedAction<Field>() {
- public Field run() {
- try {
- Field field = klass.getDeclaredField(fieldName);
- assert (field != null);
- field.setAccessible(true);
- return field;
- } catch (SecurityException se) {
- throw new RuntimeException("Error: unexpected exception caught!", se);
- } catch (NoSuchFieldException nsfe) {
- throw new RuntimeException("Error: unexpected exception caught!", nsfe);
- }
- }
- });
- }
-
- /*
- * Waits for a notification and for a boolean condition to become true.
- * The method returns when the above conditions are fullfilled or when the timeout
- * occurs.
- *
- * @param condition the object to be notified and the booelan condition to wait for
- * @param timeout the maximum time to wait in milliseconds
- * @param catchExceptions if {@code true} the method catches InterruptedException
- * @return the final boolean value of the {@code condition}
- * @throws InterruptedException if the awaiting proccess has been interrupted
- */
- public static boolean waitForConditionEx(final AtomicBoolean condition, long timeout)
- throws InterruptedException
- {
- synchronized (condition) {
- long startTime = System.currentTimeMillis();
- while (!condition.get()) {
- condition.wait(timeout);
- if (System.currentTimeMillis() - startTime >= timeout ) {
- break;
- }
- }
- }
- return condition.get();
- }
-
- /*
- * The same as {@code waitForConditionEx(AtomicBoolean, long)} except that it
- * doesn't throw InterruptedException.
- */
- public static boolean waitForCondition(final AtomicBoolean condition, long timeout) {
- try {
- return waitForConditionEx(condition, timeout);
- } catch (InterruptedException e) {
- throw new RuntimeException("Error: unexpected exception caught!", e);
- }
- }
-
- /*
- * The same as {@code waitForConditionEx(AtomicBoolean, long)} but without a timeout.
- */
- public static void waitForConditionEx(final AtomicBoolean condition)
- throws InterruptedException
- {
- synchronized (condition) {
- while (!condition.get()) {
- condition.wait();
- }
- }
- }
-
- /*
- * The same as {@code waitForConditionEx(AtomicBoolean)} except that it
- * doesn't throw InterruptedException.
- */
- public static void waitForCondition(final AtomicBoolean condition) {
- try {
- waitForConditionEx(condition);
- } catch (InterruptedException e) {
- throw new RuntimeException("Error: unexpected exception caught!", e);
- }
- }
-
- public static void waitTillShownEx(final Component comp) throws InterruptedException {
- while (true) {
- try {
- Thread.sleep(100);
- comp.getLocationOnScreen();
- break;
- } catch (IllegalComponentStateException e) {}
- }
- }
- public static void waitTillShown(final Component comp) {
- try {
- waitTillShownEx(comp);
- } catch (InterruptedException e) {
- throw new RuntimeException("Error: unexpected exception caught!", e);
- }
- }
-
- /**
- * Drags from one point to another with the specified mouse button pressed.
- *
- * @param robot a robot to use for moving the mouse, etc.
- * @param startPoint a start point of the drag
- * @param endPoint an end point of the drag
- * @param button one of {@code InputEvent.BUTTON1_MASK},
- * {@code InputEvent.BUTTON2_MASK}, {@code InputEvent.BUTTON3_MASK}
- *
- * @throws IllegalArgumentException if {@code button} is not one of
- * {@code InputEvent.BUTTON1_MASK}, {@code InputEvent.BUTTON2_MASK},
- * {@code InputEvent.BUTTON3_MASK}
- */
- public static void drag(Robot robot, Point startPoint, Point endPoint, int button) {
- if (!(button == InputEvent.BUTTON1_MASK || button == InputEvent.BUTTON2_MASK
- || button == InputEvent.BUTTON3_MASK))
- {
- throw new IllegalArgumentException("invalid mouse button");
- }
-
- robot.mouseMove(startPoint.x, startPoint.y);
- robot.mousePress(button);
- try {
- mouseMove(robot, startPoint, endPoint);
- } finally {
- robot.mouseRelease(button);
- }
- }
-
- /**
- * Moves the mouse pointer from one point to another.
- * Uses Bresenham's algorithm.
- *
- * @param robot a robot to use for moving the mouse
- * @param startPoint a start point of the drag
- * @param endPoint an end point of the drag
- */
- public static void mouseMove(Robot robot, Point startPoint, Point endPoint) {
- int dx = endPoint.x - startPoint.x;
- int dy = endPoint.y - startPoint.y;
-
- int ax = Math.abs(dx) * 2;
- int ay = Math.abs(dy) * 2;
-
- int sx = signWOZero(dx);
- int sy = signWOZero(dy);
-
- int x = startPoint.x;
- int y = startPoint.y;
-
- int d = 0;
-
- if (ax > ay) {
- d = ay - ax/2;
- while (true){
- robot.mouseMove(x, y);
- robot.delay(50);
-
- if (x == endPoint.x){
- return;
- }
- if (d >= 0){
- y = y + sy;
- d = d - ax;
- }
- x = x + sx;
- d = d + ay;
- }
- } else {
- d = ax - ay/2;
- while (true){
- robot.mouseMove(x, y);
- robot.delay(50);
-
- if (y == endPoint.y){
- return;
- }
- if (d >= 0){
- x = x + sx;
- d = d - ay;
- }
- y = y + sy;
- d = d + ax;
- }
- }
- }
-
- private static int signWOZero(int i){
- return (i > 0)? 1: -1;
- }
-
- private static int sign(int n) {
- return n < 0 ? -1 : n == 0 ? 0 : 1;
- }
-
- /** Returns {@code WindowListener} instance that diposes {@code Window} on
- * "window closing" event.
- *
- * @return the {@code WindowListener} instance that could be set
- * on a {@code Window}. After that
- * the {@code Window} is disposed when "window closed"
- * event is sent to the {@code Window}
- */
- public static WindowListener getClosingWindowAdapter() {
- return new WindowAdapter () {
- public void windowClosing(WindowEvent e) {
- e.getWindow().dispose();
- }
- };
- }
-
- /*
- * The values directly map to the ones of
- * sun.awt.X11.XWM & sun.awt.motif.MToolkit classes.
- */
- public final static int
- UNDETERMINED_WM = 1,
- NO_WM = 2,
- OTHER_WM = 3,
- OPENLOOK_WM = 4,
- MOTIF_WM = 5,
- CDE_WM = 6,
- ENLIGHTEN_WM = 7,
- KDE2_WM = 8,
- SAWFISH_WM = 9,
- ICE_WM = 10,
- METACITY_WM = 11,
- COMPIZ_WM = 12,
- LG3D_WM = 13;
-
- /*
- * Returns -1 in case of not X Window or any problems.
- */
- public static int getWMID() {
- Class clazz = null;
- try {
- if ("sun.awt.X11.XToolkit".equals(Toolkit.getDefaultToolkit().getClass().getName())) {
- clazz = Class.forName("sun.awt.X11.XWM");
- } else if ("sun.awt.motif.MToolkit".equals(Toolkit.getDefaultToolkit().getClass().getName())) {
- clazz = Class.forName("sun.awt.motif.MToolkit");
- }
- } catch (ClassNotFoundException cnfe) {
- cnfe.printStackTrace();
- }
- if (clazz == null) {
- return -1;
- }
-
- try {
- final Class _clazz = clazz;
- Method m_getWMID = (Method)AccessController.doPrivileged(new PrivilegedAction() {
- public Object run() {
- try {
- Method method = _clazz.getDeclaredMethod("getWMID", new Class[] {});
- if (method != null) {
- method.setAccessible(true);
- }
- return method;
- } catch (NoSuchMethodException e) {
- assert false;
- } catch (SecurityException e) {
- assert false;
- }
- return null;
- }
- });
- return ((Integer)m_getWMID.invoke(null, new Object[] {})).intValue();
- } catch (IllegalAccessException iae) {
- iae.printStackTrace();
- } catch (InvocationTargetException ite) {
- ite.printStackTrace();
- }
- return -1;
- }
-
-
- ////////////////////////////
- // Some stuff to test focus.
- ////////////////////////////
-
- private static WindowGainedFocusListener wgfListener = new WindowGainedFocusListener();
- private static FocusGainedListener fgListener = new FocusGainedListener();
- private static ActionPerformedListener apListener = new ActionPerformedListener();
-
- private abstract static class EventListener {
- AtomicBoolean notifier = new AtomicBoolean(false);
- Component comp;
- boolean printEvent;
-
- public void listen(Component comp, boolean printEvent) {
- this.comp = comp;
- this.printEvent = printEvent;
- notifier.set(false);
- setListener(comp);
- }
-
- public AtomicBoolean getNotifier() {
- return notifier;
- }
-
- abstract void setListener(Component comp);
-
- void printAndNotify(AWTEvent e) {
- if (printEvent) {
- System.err.println(e);
- }
- synchronized (notifier) {
- notifier.set(true);
- notifier.notifyAll();
- }
- }
- }
-
- private static class WindowGainedFocusListener extends EventListener implements WindowFocusListener {
-
- void setListener(Component comp) {
- ((Window)comp).addWindowFocusListener(this);
- }
-
- public void windowGainedFocus(WindowEvent e) {
-
- ((Window)comp).removeWindowFocusListener(this);
- printAndNotify(e);
- }
-
- public void windowLostFocus(WindowEvent e) {}
- }
-
- private static class FocusGainedListener extends EventListener implements FocusListener {
-
- void setListener(Component comp) {
- comp.addFocusListener(this);
- }
-
- public void focusGained(FocusEvent e) {
- comp.removeFocusListener(this);
- printAndNotify(e);
- }
-
- public void focusLost(FocusEvent e) {}
- }
-
- private static class ActionPerformedListener extends EventListener implements ActionListener {
-
- void setListener(Component comp) {
- ((Button)comp).addActionListener(this);
- }
-
- public void actionPerformed(ActionEvent e) {
- ((Button)comp).removeActionListener(this);
- printAndNotify(e);
- }
- }
-
- private static boolean trackEvent(int eventID, Component comp, Runnable action, int time, boolean printEvent) {
- EventListener listener = null;
-
- switch (eventID) {
- case WindowEvent.WINDOW_GAINED_FOCUS:
- listener = wgfListener;
- break;
- case FocusEvent.FOCUS_GAINED:
- listener = fgListener;
- break;
- case ActionEvent.ACTION_PERFORMED:
- listener = apListener;
- break;
- }
-
- listener.listen(comp, printEvent);
- action.run();
- return Util.waitForCondition(listener.getNotifier(), time);
- }
-
- /*
- * Tracks WINDOW_GAINED_FOCUS event for a window caused by an action.
- * @param window the window to track the event for
- * @param action the action to perform
- * @param time the max time to wait for the event
- * @param printEvent should the event received be printed or doesn't
- * @return true if the event has been received, otherwise false
- */
- public static boolean trackWindowGainedFocus(Window window, Runnable action, int time, boolean printEvent) {
- return trackEvent(WindowEvent.WINDOW_GAINED_FOCUS, window, action, time, printEvent);
- }
-
- /*
- * Tracks FOCUS_GAINED event for a component caused by an action.
- * @see #trackWindowGainedFocus
- */
- public static boolean trackFocusGained(Component comp, Runnable action, int time, boolean printEvent) {
- return trackEvent(FocusEvent.FOCUS_GAINED, comp, action, time, printEvent);
- }
-
- /*
- * Tracks ACTION_PERFORMED event for a button caused by an action.
- * @see #trackWindowGainedFocus
- */
- public static boolean trackActionPerformed(Button button, Runnable action, int time, boolean printEvent) {
- return trackEvent(ActionEvent.ACTION_PERFORMED, button, action, time, printEvent);
- }
-
- /*
- * Requests focus on the component provided and waits for the result.
- * @return true if the component has been focused, false otherwise.
- */
- public static boolean focusComponent(Component comp, int time) {
- return focusComponent(comp, time, false);
- }
- public static boolean focusComponent(final Component comp, int time, boolean printEvent) {
- return trackFocusGained(comp,
- new Runnable() {
- public void run() {
- comp.requestFocus();
- }
- },
- time, printEvent);
-
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/color/LoadStandardProfilesTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2014, 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 8039271
+ * @summary test all standard profiles load correctly.
+ */
+
+import java.awt.color.ICC_Profile;
+
+public class LoadStandardProfilesTest {
+
+ public static void main(String args[]) {
+ try {
+ ICC_Profile sRGB = ICC_Profile.getInstance("sRGB.pf");
+ ICC_Profile gray = ICC_Profile.getInstance("GRAY.pf");
+ ICC_Profile pycc = ICC_Profile.getInstance("PYCC.pf");
+ ICC_Profile ciexyz = ICC_Profile.getInstance("CIEXYZ.pf");
+ ICC_Profile linearRGB = ICC_Profile.getInstance("LINEAR_RGB.pf");
+
+ if (sRGB == null ||
+ gray == null ||
+ pycc == null ||
+ ciexyz == null ||
+ linearRGB == null)
+ {
+ throw new RuntimeException("null profile.");
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/security/AccessController/DoPrivAccomplice.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2007, 2014, 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.
+ */
+
+public class DoPrivAccomplice {
+
+ public String go() {
+ String name = (String)java.security.AccessController.
+ doPrivileged((java.security.PrivilegedAction)() ->
+ System.getProperty("user.name"));
+ return name;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/security/AccessController/DoPrivAccompliceTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2007, 2014, 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.
+ */
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @test
+ * @bug 8048362
+ * @compile ../../../lib/testlibrary/JavaToolUtils.java
+ * DoPrivAccomplice.java DoPrivTest.java
+ * @summary Tests the doPrivileged with accomplice Generate two jars
+ * (DoPrivTest.jar and DoPrivAccomplice.jar) and grant permission to
+ * DoPrivAccmplice.jar for reading user.home property from a PrivilagedAction.
+ * Run DoPrivTest.jar and try to access user.home property using
+ * DoPrivAccmplice.jar.
+ * @run main/othervm DoPrivAccompliceTest
+ */
+
+public class DoPrivAccompliceTest {
+
+ private static final String PWD = System.getProperty("test.classes", "./");
+ private static final String ACTION_SOURCE = "DoPrivAccomplice";
+ private static final String TEST_SOURCE = "DoPrivTest";
+
+ public static void createPolicyFile(URI codebaseURL) throws IOException {
+ String codebase = codebaseURL.toString();
+ String quotes = "\"";
+ StringBuilder policyFile = new StringBuilder();
+ policyFile.append("grant codeBase ").append(quotes).
+ append(codebase).append(quotes).append("{\n").
+ append("permission java.util.PropertyPermission ").
+ append(quotes).append("user.name").append(quotes).
+ append(",").append(quotes).append("read").append(quotes).
+ append(";\n};");
+ try (FileWriter writer = new FileWriter(new File(PWD, "java.policy"))) {
+ writer.write(policyFile.toString());
+ writer.close();
+ } catch (IOException e) {
+ System.err.println("Error while creating policy file");
+ throw e;
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ final File class1 = new File(PWD, ACTION_SOURCE + ".class");
+ final File class2 = new File(PWD, TEST_SOURCE + ".class");
+ final File jarFile1 = new File(PWD, ACTION_SOURCE + ".jar");
+ final File jarFile2 = new File(PWD, TEST_SOURCE + ".jar");
+ System.out.println("Compilation successfull");
+ JavaToolUtils.createJar(jarFile1, Arrays.asList(new File[]{class1}));
+ System.out.println("Created jar file " + jarFile1);
+ JavaToolUtils.createJar(jarFile2, Arrays.asList(new File[]{class2}));
+ System.out.println("Created jar file " + jarFile2);
+ createPolicyFile(jarFile1.toURI());
+
+ List<String> commands = new ArrayList<>();
+ final String pathSepartor = System.getProperty("path.separator");
+ commands.add("-Djava.security.manager");
+ commands.add("-Djava.security.policy=" + PWD + "/java.policy");
+ commands.add("-classpath");
+ commands.add(PWD + "/" + TEST_SOURCE + ".jar" + pathSepartor
+ + PWD + "/" + ACTION_SOURCE + ".jar");
+ commands.add(TEST_SOURCE);
+ if (JavaToolUtils.runJava(commands) == 0) {
+ System.out.println("Test PASSES");
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/security/AccessController/DoPrivTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2007, 2014, 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.
+ */
+
+public class DoPrivTest {
+
+ public static void main(String[] args) {
+ String name = new DoPrivAccomplice().go();
+ System.out.println("Received Name : " + name);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/security/KeyStore/TestKeyStoreBasic.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2001, 2014, 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 static java.lang.System.out;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.Provider;
+import java.security.Security;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+/*
+ * @test
+ * @bug 8048621
+ * @summary Test the basic operations of KeyStore, provided by SunJCE (jceks),
+ * and SunPKCS11-Solaris(PKCS11KeyStore)
+ * @author Yu-Ching Valerie PENG
+ */
+
+public class TestKeyStoreBasic {
+ private static final char[] PASSWD2 = new char[] {
+ 'b', 'o', 'r', 'e', 'd'
+ };
+ private static final char[] PASSWDK = new String("cannot be null")
+ .toCharArray();
+ private static final String[] KS_Type = {
+ "jks", "jceks", "pkcs12", "PKCS11KeyStore"
+ };
+ private static final String[] PRO_TYPE = {
+ "SUN", "SunJCE", "SunJSSE", "SunPKCS11-Solaris"
+ };
+ private static final String ALIAS_HEAD = "test";
+
+ public static void main(String args[]) throws Exception {
+ TestKeyStoreBasic jstest = new TestKeyStoreBasic();
+ jstest.run();
+ }
+
+ public void run() throws Exception {
+ Provider[] providers = Security.getProviders();
+ for (Provider p: providers) {
+ String prvName = p.getName();
+ if (prvName.startsWith("SunJCE")
+ || prvName.startsWith("SunPKCS11-Solaris")) {
+ try {
+ runTest(p);
+ out.println("Test with provider " + p.getName() + ""
+ + " passed");
+ } catch (java.security.KeyStoreException e) {
+ if (prvName.startsWith("SunPKCS11-Solaris")) {
+ out.println("KeyStoreException is expected "
+ + "PKCS11KeyStore is invalid keystore type.");
+ e.printStackTrace();
+ } else {
+ throw e;
+ }
+ }
+ }
+ }
+ }
+
+ public void runTest(Provider p) throws Exception {
+ SecretKey key = new SecretKeySpec(
+ new String("No one knows").getBytes(), "PBE");
+ int numEntries = 5;
+ String proName = p.getName();
+ String type = null;
+ for (int i = 0; i < PRO_TYPE.length; i++) {
+ if (proName.compareTo(PRO_TYPE[i]) == 0) {
+ type = KS_Type[i];
+ break;
+ }
+ }
+ KeyStore ks = KeyStore.getInstance(type, p);
+ KeyStore ks2 = KeyStore.getInstance(type, ks.getProvider().getName());
+
+ // create an empty key store
+ ks.load(null, null);
+
+ // store the secret keys
+ for (int j = 0; j < numEntries; j++) {
+ ks.setKeyEntry(ALIAS_HEAD + j, key, PASSWDK, null);
+ }
+
+ // initialize the 2nd key store object with the 1st one
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ks.store(baos, PASSWDK);
+ byte[] bArr = baos.toByteArray();
+ ByteArrayInputStream bais = new ByteArrayInputStream(bArr);
+ ks2.load(bais, null);
+
+ // check 2nd key store type
+ checkType(ks2, type);
+ // check the existing aliases for the 2nd key store
+ checkAlias(ks2, numEntries);
+
+ // compare the creation date of the 2 key stores for all aliases
+ compareCreationDate(ks, ks2, numEntries);
+ // remove the last entry from the 2nd key store
+ numEntries--;
+ ks2.deleteEntry(ALIAS_HEAD + numEntries);
+
+ // re-initialize the 1st key store with the 2nd key store
+ baos.reset();
+ ks2.store(baos, PASSWD2);
+ bais = new ByteArrayInputStream(baos.toByteArray());
+ try {
+ // expect an exception since the password is incorrect
+ ks.load(bais, PASSWDK);
+ throw new RuntimeException(
+ "ERROR: passed the loading with incorrect password");
+ } catch (IOException ex) {
+ bais.reset();
+ ks.load(bais, PASSWD2);
+ bais.reset();
+ ks.load(bais, null);
+ } finally {
+ bais.close();
+ baos.close();
+ }
+
+ // check key store type
+ checkType(ks, type);
+
+ // check the existing aliases
+ checkAlias(ks, numEntries);
+
+ // compare the creation date of the 2 key stores for all aliases
+ compareCreationDate(ks, ks2, numEntries);
+
+ }
+
+ // check key store type
+ private void checkType(KeyStore obj, String type) {
+ if (!obj.getType().equals(type)) {
+ throw new RuntimeException("ERROR: wrong key store type");
+
+ }
+ }
+
+ // check the existing aliases
+ private void checkAlias(KeyStore obj, int range) throws KeyStoreException {
+ for (int k = 0; k < range; k++) {
+ if (!obj.containsAlias(ALIAS_HEAD + k)) {
+ throw new RuntimeException("ERROR: alias (" + k
+ + ") should exist");
+
+ }
+ }
+ }
+
+ // compare the creation dates - true if all the same
+ private void compareCreationDate(KeyStore o1, KeyStore o2, int range)
+ throws KeyStoreException {
+ boolean result = true;
+ String alias = null;
+ for (int k = 0; k < range; k++) {
+ alias = ALIAS_HEAD + k;
+ if (!o1.getCreationDate(alias).equals(o2.getCreationDate(alias))) {
+ throw new RuntimeException("ERROR: entry creation time (" + k
+ + ") differs");
+
+ }
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/security/KeyStore/TestKeyStoreEntry.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2001, 2014, 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 static java.lang.System.out;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.Provider;
+import java.security.Security;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+/*
+ * @test
+ * @bug 8048621
+ * @summary Test the basic operations of KeyStore entry, provided by SunJCE
+ * (jceks), and SunPKCS11-Solaris(PKCS11KeyStore)
+ * @author Yu-Ching Valerie PENG
+ */
+
+public class TestKeyStoreEntry {
+ private static final char[] PASSWDK = new char[] {
+ 't', 'e', 'r', 'c', 'e', 's'
+ };
+ private static final char[] PASSWDF = new String("guardian Angel")
+ .toCharArray();
+ private static final String[] KS_ALGOS = {
+ "DES", "DESede", "Blowfish"
+ };
+ private static final int NUM_ALGOS = KS_ALGOS.length;
+
+ private static final String[] KS_TYPE = {
+ "jks", "jceks", "pkcs12", "PKCS11KeyStore"
+ };
+ private static final String[] PRO_TYPE = {
+ "SUN", "SunJCE", "SunJSSE", "SunPKCS11-Solaris"
+ };
+
+ private final SecretKey[] sks = new SecretKey[NUM_ALGOS];
+
+ TestKeyStoreEntry() throws Exception {
+ // generate secret keys which are to be stored in the jce
+ // key store object
+ KeyGenerator[] kgs = new KeyGenerator[NUM_ALGOS];
+ for (int i = 0; i < NUM_ALGOS; i++) {
+ kgs[i] = KeyGenerator.getInstance(KS_ALGOS[i], "SunJCE");
+ sks[i] = kgs[i].generateKey();
+ }
+
+ }
+
+ public static void main(String args[]) throws Exception {
+ TestKeyStoreEntry jstest = new TestKeyStoreEntry();
+ jstest.run();
+ }
+
+ public void run() throws Exception {
+
+ Provider[] providers = Security.getProviders();
+ for (Provider p: providers) {
+ String prvName = p.getName();
+ if (prvName.startsWith("SunJCE")
+ || prvName.startsWith("SunPKCS11-Solaris")) {
+ try {
+ runTest(p);
+ out.println("Test with provider " + p.getName() + ""
+ + " passed");
+
+ } catch (java.security.KeyStoreException e) {
+ if (prvName.startsWith("SunPKCS11-Solaris")) {
+ out.println("KeyStoreException is expected because "
+ + "PKCS11KeyStore is invalid keystore type.");
+ e.printStackTrace();
+ } else {
+ throw e;
+ }
+ }
+ }
+ }
+ }
+
+ public void runTest(Provider p) throws Exception {
+ try (FileOutputStream fos = new FileOutputStream("jceks");
+ FileInputStream fis = new FileInputStream("jceks");) {
+
+ KeyStore ks = KeyStore.getInstance("jceks", p);
+ // create an empty key store
+ ks.load(null, null);
+
+ // store the secret keys
+ String aliasHead = new String("secretKey");
+ for (int j = 0; j < NUM_ALGOS; j++) {
+ ks.setKeyEntry(aliasHead + j, sks[j], PASSWDK, null);
+ }
+
+ // write the key store out to a file
+ ks.store(fos, PASSWDF);
+ // wipe clean the existing key store
+ for (int k = 0; k < NUM_ALGOS; k++) {
+ ks.deleteEntry(aliasHead + k);
+ }
+ if (ks.size() != 0) {
+ throw new RuntimeException("ERROR: re-initialization failed");
+ }
+
+ // reload the key store with the file
+ ks.load(fis, PASSWDF);
+
+ // check the integrity/validaty of the key store
+ Key temp = null;
+ String alias = null;
+ if (ks.size() != NUM_ALGOS) {
+ throw new RuntimeException("ERROR: wrong number of key"
+ + " entries");
+ }
+
+ for (int m = 0; m < ks.size(); m++) {
+ alias = aliasHead + m;
+ temp = ks.getKey(alias, PASSWDK);
+ // compare the keys
+ if (!temp.equals(sks[m])) {
+ throw new RuntimeException("ERROR: key comparison (" + m
+ + ") failed");
+ }
+ // check the type of key
+ if (ks.isCertificateEntry(alias) || !ks.isKeyEntry(alias)) {
+ throw new RuntimeException("ERROR: type identification ("
+ + m + ") failed");
+ }
+ }
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/sql/test/sql/DriverManagerPermissionsTests.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2014, 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 test.sql;
+
+import java.security.AccessControlException;
+import java.security.Policy;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import util.BaseTest;
+import util.StubDriver;
+import util.TestPolicy;
+
+public class DriverManagerPermissionsTests extends BaseTest {
+
+ private static Policy policy;
+ private static SecurityManager sm;
+
+ /*
+ * Install a SecurityManager along with a base Policy to allow testNG to run
+ */
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ setPolicy(new TestPolicy());
+ System.setSecurityManager(new SecurityManager());
+ }
+
+ /*
+ * Install the original Policy and SecurityManager
+ */
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ System.setSecurityManager(sm);
+ setPolicy(policy);
+ }
+
+ /*
+ * Save off the original Policy and SecurityManager
+ */
+ public DriverManagerPermissionsTests() {
+ policy = Policy.getPolicy();
+ sm = System.getSecurityManager();
+ }
+
+ /*
+ * Validate that AccessControlException is thrown if SQLPermission("setLog")
+ * has not been granted
+ */
+ @Test(expectedExceptions = AccessControlException.class)
+ public void test() {
+ setPolicy(new TestPolicy());
+ DriverManager.setLogStream(null);
+ }
+
+ /*
+ * Validate that setLogStream succeeds if SQLPermission("setLog") has been
+ * granted
+ */
+ @Test
+ public void test1() {
+ Policy.setPolicy(new TestPolicy("setLog"));
+ DriverManager.setLogStream(null);
+ }
+
+ /*
+ * Validate that setLogStream succeeds if AllPermissions has been granted
+ */
+ @Test
+ public void test2() {
+ setPolicy(new TestPolicy("all"));
+ DriverManager.setLogStream(null);
+ }
+
+ /*
+ * Validate that AccessControlException is thrown if SQLPermission("setLog")
+ * has not been granted
+ */
+ @Test(expectedExceptions = AccessControlException.class)
+ public void test4() {
+ setPolicy(new TestPolicy());
+ DriverManager.setLogWriter(null);
+ }
+
+ /*
+ * Validate that setLogWriter succeeds if SQLPermission("setLog") has been
+ * granted
+ */
+ @Test
+ public void test5() {
+ setPolicy(new TestPolicy("setLog"));
+ DriverManager.setLogWriter(null);
+ }
+
+ /*
+ * Validate that setLogWriter succeeds if AllPermissions has been granted
+ */
+ @Test
+ public void test6() {
+ setPolicy(new TestPolicy("all"));
+ DriverManager.setLogWriter(null);
+ }
+
+ /*
+ * Validate that AccessControlException is thrown if
+ * SQLPermission("deregisterDriver") has not been granted
+ */
+ @Test(expectedExceptions = AccessControlException.class)
+ public void test7() throws SQLException {
+ setPolicy(new TestPolicy());
+ DriverManager.deregisterDriver(new StubDriver());
+ }
+
+ /*
+ * Validate that deregisterDriver succeeds if
+ * SQLPermission("deregisterDriver") has been granted
+ */
+ @Test
+ public void test8() throws SQLException {
+ setPolicy(new TestPolicy("deregisterDriver"));
+ DriverManager.deregisterDriver(new StubDriver());
+ }
+
+ /*
+ * Validate that deregisterDriver succeeds if AllPermissions has been
+ * granted
+ */
+ @Test
+ public void test9() throws SQLException {
+ setPolicy(new TestPolicy("all"));
+ DriverManager.deregisterDriver(new StubDriver());
+ }
+}
--- a/jdk/test/java/sql/util/BaseTest.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/test/java/sql/util/BaseTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -27,6 +27,7 @@
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import java.security.Policy;
import java.sql.SQLException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
@@ -88,4 +89,11 @@
}
return o1;
}
+
+ /*
+ * Utility Method used to set the current Policy
+ */
+ protected static void setPolicy(Policy p) {
+ Policy.setPolicy(p);
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/sql/util/TestPolicy.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2014, 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 util;
+
+import java.io.FilePermission;
+import java.security.AllPermission;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import java.security.SecurityPermission;
+import java.sql.SQLPermission;
+import java.util.Enumeration;
+import java.util.PropertyPermission;
+import java.util.StringJoiner;
+
+/*
+ * Simple Policy class that supports the required Permissions to validate the
+ * JDBC concrete classes
+ */
+public class TestPolicy extends Policy {
+
+ final PermissionCollection permissions = new Permissions();
+
+ /**
+ * Constructor which sets the minimum permissions allowing testNG to work
+ * with a SecurityManager
+ */
+ public TestPolicy() {
+ setMinimalPermissions();
+ }
+
+ /*
+ * Constructor which determines which permissions are defined for this
+ * Policy used by the JDBC tests Possible values are: all (ALLPermissions),
+ * setLog (SQLPemission("setLog"), deregisterDriver
+ * (SQLPermission("deregisterDriver") (SQLPermission("deregisterDriver"),
+ * and setSyncFactory(SQLPermission(setSyncFactory),
+ *
+ * @param policy Permissions to set
+ */
+ public TestPolicy(String policy) {
+
+ switch (policy) {
+ case "all":
+ permissions.add(new AllPermission());
+ break;
+ case "setLog":
+ setMinimalPermissions();
+ permissions.add(new SQLPermission("setLog"));
+ break;
+ case "deregisterDriver":
+ setMinimalPermissions();
+ permissions.add(new SQLPermission("deregisterDriver"));
+ break;
+ case "setSyncFactory":
+ setMinimalPermissions();
+ permissions.add(new SQLPermission("setSyncFactory"));
+ break;
+ default:
+ setMinimalPermissions();
+ }
+ }
+
+ /*
+ * Defines the minimal permissions required by testNG when running these
+ * tests
+ */
+ private void setMinimalPermissions() {
+ permissions.add(new SecurityPermission("getPolicy"));
+ permissions.add(new SecurityPermission("setPolicy"));
+ permissions.add(new RuntimePermission("getClassLoader"));
+ permissions.add(new RuntimePermission("setSecurityManager"));
+ permissions.add(new RuntimePermission("createSecurityManager"));
+ permissions.add(new PropertyPermission("testng.show.stack.frames",
+ "read"));
+ permissions.add(new PropertyPermission("line.separator", "read"));
+ permissions.add(new PropertyPermission("fileStringBuffer", "read"));
+ permissions.add(new PropertyPermission("dataproviderthreadcount", "read"));
+ permissions.add(new PropertyPermission("java.io.tmpdir", "read"));
+ permissions.add(new FilePermission("<<ALL FILES>>",
+ "read, write, delete"));
+ }
+
+ /*
+ * Overloaded methods from the Policy class
+ */
+ @Override
+ public String toString() {
+ StringJoiner sj = new StringJoiner("\n", "policy: ", "");
+ Enumeration<Permission> perms = permissions.elements();
+ while (perms.hasMoreElements()) {
+ sj.add(perms.nextElement().toString());
+ }
+ return sj.toString();
+
+ }
+
+ @Override
+ public PermissionCollection getPermissions(ProtectionDomain domain) {
+ return permissions;
+ }
+
+ @Override
+ public PermissionCollection getPermissions(CodeSource codesource) {
+ return permissions;
+ }
+
+ @Override
+ public boolean implies(ProtectionDomain domain, Permission perm) {
+ return permissions.implies(perm);
+ }
+}
--- a/jdk/test/java/util/Currency/tablea1.txt Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/test/java/util/Currency/tablea1.txt Wed Jul 05 19:59:54 2017 +0200
@@ -1,12 +1,12 @@
#
#
-# Amendments up until ISO 4217 AMENDMENT NUMBER 156
-# (As of 23 July 2013)
+# Amendments up until ISO 4217 AMENDMENT NUMBER 159
+# (As of 15 August 2014)
#
# Version
FILEVERSION=1
-DATAVERSION=156
+DATAVERSION=159
# ISO 4217 currency data
AF AFN 971 2
@@ -142,7 +142,7 @@
LR LRD 430 2
LY LYD 434 3
LI CHF 756 2
-LT LTL 440 2
+LT LTL 440 2 2014-12-31-22-00-00 EUR 978 2
LU EUR 978 2
MO MOP 446 2
MK MKD 807 2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/TLS/CipherTestUtils.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,687 @@
+/**
+ * Copyright (c) 2010, 2014, 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.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.security.KeyFactory;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.List;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * Test that all ciphersuites work in all versions and all client authentication
+ * types. The way this is setup the server is stateless and all checking is done
+ * on the client side.
+ */
+
+public class CipherTestUtils {
+
+ public static final int TIMEOUT = 20 * 1000;
+ public static final SecureRandom secureRandom = new SecureRandom();
+ public static char[] PASSWORD = "passphrase".toCharArray();
+ private static final List<TestParameters> TESTS = new ArrayList<>(3);
+ private static final List<Exception> EXCEPTIONS = new ArrayList<>(1);
+ private static final String CLIENT_PUBLIC_KEY
+ = "-----BEGIN CERTIFICATE-----\n"
+ + "MIICtTCCAh4CCQDkYJ46DMcGRjANBgkqhkiG9w0BAQUFADCBnDELMAkGA1UEBhMC\n"
+ + "VVMxCzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MR8wHQYDVQQK\n"
+ + "DBZTdW4gTWljcm9zeXN0ZW1zLCBJbmMuMSYwJAYDVQQLDB1TdW4gTWljcm9zeXN0\n"
+ + "ZW1zIExhYm9yYXRvcmllczEfMB0GA1UEAwwWVGVzdCBDQSAoMTAyNCBiaXQgUlNB\n"
+ + "KTAeFw0wOTA0MjcwNDA0MDhaFw0xMzA2MDUwNDA0MDhaMIGgMQswCQYDVQQGEwJV\n"
+ + "UzELMAkGA1UECAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxHzAdBgNVBAoM\n"
+ + "FlN1biBNaWNyb3N5c3RlbXMsIEluYy4xJjAkBgNVBAsMHVN1biBNaWNyb3N5c3Rl\n"
+ + "bXMgTGFib3JhdG9yaWVzMSMwIQYDVQQDDBpUZXN0IENsaWVudCAoMTAyNCBiaXQg\n"
+ + "UlNBKTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAm5rwjmhO7Nwd5GWs+KvQ\n"
+ + "UnDiqpRDvRriOUFdF0rCI2Op24C+iwUMDGxPsgP7VkUpOdJhw3c72aP0CAWcZ5dN\n"
+ + "UCW7WVDAxnogCahLCir1jjoGdEjiNGOy0L9sypsM9UvBzJN8uvXsxsTZX4Z88cKU\n"
+ + "G7RUvN8LQ88zDljk5zr3c2MCAwEAATANBgkqhkiG9w0BAQUFAAOBgQA7LUDrzHln\n"
+ + "EXuGmwZeeroACB6DVtkClMskF/Pj5GnTxoeNN9DggycX/eOeIDKRloHuMpBeZPJH\n"
+ + "NUwFu4LB6HBDeldQD9iRp8zD/fPakOdN+1Gk5hciIZZJ5hQmeCl7Va2Gr64vUqZG\n"
+ + "MkVU755t+7ByLgzWuhPhhsX9QCuPR5FjvQ==\n"
+ + "-----END CERTIFICATE-----";
+
+ private static final String CLIENT_PRIVATE_KEY
+ = "-----BEGIN PRIVATE KEY-----\n"
+ + "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJua8I5oTuzcHeRl\n"
+ + "rPir0FJw4qqUQ70a4jlBXRdKwiNjqduAvosFDAxsT7ID+1ZFKTnSYcN3O9mj9AgF\n"
+ + "nGeXTVAlu1lQwMZ6IAmoSwoq9Y46BnRI4jRjstC/bMqbDPVLwcyTfLr17MbE2V+G\n"
+ + "fPHClBu0VLzfC0PPMw5Y5Oc693NjAgMBAAECgYA5w73zj8Nk6J3sMNaShe3S/PcY\n"
+ + "TewLopRCnwI46FbDnnbq9pNFtnzvi7HWKuY983THc1M5peTA+b1Y0QRr7F4Vg4x9\n"
+ + "9UM0B/tZcIIcJJ3LS+9fXKCbYLQWq5F05JqeZu+i+QLmJFO5+2p7laeQ4oQfW7QE\n"
+ + "YR4u2mSaLe0SsqHvOQJBAMhgcye9C6pJO0eo2/VtRxAXI7zxNAIjHwKo1cva7bhu\n"
+ + "GdrMaEAJBAsMJ1GEk7/WDI+3KEbTjQdfIJuAvOR4FXUCQQDGzNn/tl2k93v/ugyM\n"
+ + "/tBhCKDipYDIbyJMoG2AOtOGmCsiGo5L7idO4OAcm/QiHBQMXjFIVgTUcH8MhGj4\n"
+ + "blJ3AkA5fUqsxRV6tuYWKkFpif/QgwMS65VDY7Y6+hvVECwSNSyf1PO4I54QWV1S\n"
+ + "ixok+RHDjgY1Q+77hXSCiQ4o8rcdAkBHvjfR+5sx5IpgUGElJPRIgFenU3j1XH3x\n"
+ + "T1gVFaWuhg3S4eiGaGzRH4BhcrqY8K8fg4Kfi0N08yA2gTZsqUujAkEAjuNPTuKx\n"
+ + "ti0LXI09kbGUqOpRMm1zW5TD6LFeEaUN6oxrSZI2YUvu7VyotAqsxX5O0u0f3VQw\n"
+ + "ySF0Q1oZ6qu7cg==\n"
+ + "-----END PRIVATE KEY-----";
+ private static final String SERVER_PUBLIC_KEY
+ = "-----BEGIN CERTIFICATE-----\n"
+ + "MIICtTCCAh4CCQDkYJ46DMcGRTANBgkqhkiG9w0BAQUFADCBnDELMAkGA1UEBhMC\n"
+ + "VVMxCzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MR8wHQYDVQQK\n"
+ + "DBZTdW4gTWljcm9zeXN0ZW1zLCBJbmMuMSYwJAYDVQQLDB1TdW4gTWljcm9zeXN0\n"
+ + "ZW1zIExhYm9yYXRvcmllczEfMB0GA1UEAwwWVGVzdCBDQSAoMTAyNCBiaXQgUlNB\n"
+ + "KTAeFw0wOTA0MjcwNDA0MDhaFw0xMzA2MDUwNDA0MDhaMIGgMQswCQYDVQQGEwJV\n"
+ + "UzELMAkGA1UECAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxHzAdBgNVBAoM\n"
+ + "FlN1biBNaWNyb3N5c3RlbXMsIEluYy4xJjAkBgNVBAsMHVN1biBNaWNyb3N5c3Rl\n"
+ + "bXMgTGFib3JhdG9yaWVzMSMwIQYDVQQDDBpUZXN0IFNlcnZlciAoMTAyNCBiaXQg\n"
+ + "UlNBKTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArsHHeZ1O67yuxQKDSAOC\n"
+ + "Xm271ViwBrXkxe5cvhG8MCCem6Z3XeZ/m6c2ucRwLaQxnmG1m0G6/OYaUXTivjcG\n"
+ + "/K4bc1I+yjghAWQNLBtsOiP9w0LKibg3TSDehpeuuz/lmB5A4HMqQr8KkY4K7peD\n"
+ + "1QkJ2Dn3zhbwQ/0d8f5CCbkCAwEAATANBgkqhkiG9w0BAQUFAAOBgQBOd8XojEnu\n"
+ + "eTUHBwqfmnvRQvbICFDNbbL4KuX/JNPSy1WMGAEbNCTLZ+5yP69js8aUYqAk5vVf\n"
+ + "dWRLU3MDiEzW7zxE1ubuKWjVuyGbG8Me0G01Hw+evBcZqB64Fz3OFISVfQh7MqE/\n"
+ + "O0AeakRMH350FRLNl4o6KBSXmF/AADfqQQ==\n"
+ + "-----END CERTIFICATE-----";
+
+ private static final String SERVER_PRIVATE_KEY
+ = "-----BEGIN PRIVATE KEY-----\n"
+ + "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAK7Bx3mdTuu8rsUC\n"
+ + "g0gDgl5tu9VYsAa15MXuXL4RvDAgnpumd13mf5unNrnEcC2kMZ5htZtBuvzmGlF0\n"
+ + "4r43BvyuG3NSPso4IQFkDSwbbDoj/cNCyom4N00g3oaXrrs/5ZgeQOBzKkK/CpGO\n"
+ + "Cu6Xg9UJCdg5984W8EP9HfH+Qgm5AgMBAAECgYAXUv+3qJo+9mjxHHu/IdDFn6nB\n"
+ + "ONwNmTtWe5DfQWi3l7LznU0zOC9x6+hu9NvwC4kf1XSyqxw04tVCZ/JXZurEmEBz\n"
+ + "YtcQ5idRQDkKYXEDOeVUfvtHO6xilzrhPKxxd0GG/sei2pozikkqnYF3OcP0qL+a\n"
+ + "3nWixZQBRoF2nIRLcQJBAN97TJBr0XTRmE7OCKLUy1+ws7vZB9uQ2efHMsgwOpsY\n"
+ + "3cEW5qd95hrxLU72sBeu9loHQgBrT2Q3OAxnsPXmgO0CQQDIL3u9kS/O3Ukx+n1H\n"
+ + "JdPFQCRxrDm/vtJpQEmq+mLqxxnxCFRIYQ2ieAPokBxWeMDtdWJGD3VxhahjPfZm\n"
+ + "5K59AkEAuDVl0tVMfUIWjT5/F9jXGjUIsZofQ/iN5OLpFOHMLPO+Nd6umPjJpwON\n"
+ + "GT11wM/S+DprSPUrJ6vsYy1FTCuHsQJBAMXtnO07xgdE6AAQaRmVnyMiXmY+IQMj\n"
+ + "CyuhsrToyDDWFyIoWB0QSMjg3QxuoHYnAqpGK5qV4ksSGgG13BCz/okCQQCRHTgn\n"
+ + "DuFG2f7GYLFjI4NaTEzHGp+J9LiNYY1kYYLonpwAC3Z5hzJVanYT3/g23AUZ/fdF\n"
+ + "v5PDIViuPo5ZB1eD\n"
+ + "-----END PRIVATE KEY-----";
+
+ private static final String CA_PUBLIC_KEY
+ = "-----BEGIN CERTIFICATE-----\n"
+ + "MIIDCDCCAnGgAwIBAgIJAIYlGfwNBY6NMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD\n"
+ + "VQQGEwJVUzELMAkGA1UECAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxHzAd\n"
+ + "BgNVBAoMFlN1biBNaWNyb3N5c3RlbXMsIEluYy4xJjAkBgNVBAsMHVN1biBNaWNy\n"
+ + "b3N5c3RlbXMgTGFib3JhdG9yaWVzMR8wHQYDVQQDDBZUZXN0IENBICgxMDI0IGJp\n"
+ + "dCBSU0EpMB4XDTA5MDQyNzA0MDQwOFoXDTEzMDYwNTA0MDQwOFowgZwxCzAJBgNV\n"
+ + "BAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEfMB0G\n"
+ + "A1UECgwWU3VuIE1pY3Jvc3lzdGVtcywgSW5jLjEmMCQGA1UECwwdU3VuIE1pY3Jv\n"
+ + "c3lzdGVtcyBMYWJvcmF0b3JpZXMxHzAdBgNVBAMMFlRlc3QgQ0EgKDEwMjQgYml0\n"
+ + "IFJTQSkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOK4DJxxb0XX6MJ1CVjp\n"
+ + "9Gmr/Ua8MS12R58F9lDpSKuq8cFexA4W7OdZ4jtbKv0tRHX5YxmbnXedwS+gdcOA\n"
+ + "GRgXMoeXlgTFGpdL+TR8xKIlMGRSjnR7MpR2tRyIYI2p+UTEiD6LTlIm5Wh4z1q8\n"
+ + "LYbxyMVD1XNNNymvPM44OjsBAgMBAAGjUDBOMB0GA1UdDgQWBBT27BLUflmfdtbi\n"
+ + "WTgjwWnoxop2MTAfBgNVHSMEGDAWgBT27BLUflmfdtbiWTgjwWnoxop2MTAMBgNV\n"
+ + "HRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAEQELNzhZpjnSgigd+QJ6I/3CPDo\n"
+ + "SDkMLdP1BHlT/DkMIZvABm+M09ePNlWiLYCNCsL9nWmX0gw0rFDKsTklZyKTUzaM\n"
+ + "oy/AZCrAaoIc6SO5m1xE1RMyVxd/Y/kg6cbfWxxCJFlMeU5rsSdC97HTE/lDyuoh\n"
+ + "BmlOBB7SdR+1ScjA\n"
+ + "-----END CERTIFICATE-----";
+
+ private static final String CA_PRIVATE_KEY
+ = "-----BEGIN PRIVATE KEY-----\n"
+ + "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOK4DJxxb0XX6MJ1\n"
+ + "CVjp9Gmr/Ua8MS12R58F9lDpSKuq8cFexA4W7OdZ4jtbKv0tRHX5YxmbnXedwS+g\n"
+ + "dcOAGRgXMoeXlgTFGpdL+TR8xKIlMGRSjnR7MpR2tRyIYI2p+UTEiD6LTlIm5Wh4\n"
+ + "z1q8LYbxyMVD1XNNNymvPM44OjsBAgMBAAECgYEApmMOlk3FrQtsvjGof4GLp3Xa\n"
+ + "tmvs54FzxKhagj0C4UHelNyYpAJ9MLjNiGQ7I31yTeaNrUCAi0XSfsKTSrwbLSnJ\n"
+ + "qsUPKMBrnzcWrOyui2+cupHZXaTlNeYB97teLJYpa6Ql9CZLoTHoim1+//s7diBh\n"
+ + "03Vls+M6Poi5PMvv59UCQQD+k/BiokmbBgWHfBY5cZSlx3Z4VTwSHJmHDTO3Tjso\n"
+ + "EVErXUSVvqD/KHX6eM4VPM8lySV5djWV8lDsESCWMtiLAkEA4/xFNsiOLMQpxW/O\n"
+ + "bt2tukxJkAxldD4lPoFZR+zbXtMtt8OjERtX2wD+nj6h7jfIeSyVuBEcBN8Uj8xe\n"
+ + "kgfgIwJAPbKG4LCqHAsCjgpRrIxNVTwZByLJEy6hOqzFathn19cSj+rjs1Lm28/n\n"
+ + "f9OFRnpdTbAJB/3REM0QNZYVCrG57wJBAN0KuTytZJNouaswhPCew5Kt5mDgc/kp\n"
+ + "S8j3dk2zCto8W8Ygy1iJrzuqEjPxO+UQdrFtlde51vWuKGxnVIW3VwsCQEldqk7r\n"
+ + "8y7PgquPP+k3L0OXno5wGBrPcW1+U0mhIZGnwSzE4SPX2ddqUSEUA/Av4RjAckL/\n"
+ + "fpqmCkpTanyYW9U=\n"
+ + "-----END PRIVATE KEY-----";
+
+ private final SSLSocketFactory factory;
+ private final X509ExtendedKeyManager clientKeyManager;
+ private final X509ExtendedKeyManager serverKeyManager;
+ private final X509TrustManager clientTrustManager;
+ private final X509TrustManager serverTrustManager;
+
+ static abstract class Server implements Runnable {
+
+ final CipherTestUtils cipherTest;
+
+ Server(CipherTestUtils cipherTest) throws Exception {
+ this.cipherTest = cipherTest;
+ }
+
+ @Override
+ public abstract void run();
+
+ void handleRequest(InputStream in, OutputStream out)
+ throws IOException {
+ boolean newline = false;
+ StringBuilder sb = new StringBuilder();
+ while (true) {
+ int ch = in.read();
+ if (ch < 0) {
+ throw new EOFException();
+ }
+ sb.append((char) ch);
+ if (ch == '\r') {
+ // empty
+ } else if (ch == '\n') {
+ if (newline) {
+ // 2nd newline in a row, end of request
+ break;
+ }
+ newline = true;
+ } else {
+ newline = false;
+ }
+ }
+ String request = sb.toString();
+ if (request.startsWith("GET / HTTP/1.") == false) {
+ throw new IOException("Invalid request: " + request);
+ }
+ out.write("HTTP/1.0 200 OK\r\n\r\n".getBytes());
+ out.write("Tested Scenario: ".getBytes());
+ TestParameters tp = (TestParameters) CipherTestUtils.TESTS.get(0);
+ out.write(tp.toString().getBytes());
+ out.write(" Test PASSED.".getBytes());
+ }
+ }
+
+ public static class TestParameters {
+
+ String cipherSuite;
+ String protocol;
+ String clientAuth;
+
+ TestParameters(String cipherSuite, String protocol,
+ String clientAuth) {
+ this.cipherSuite = cipherSuite;
+ this.protocol = protocol;
+ this.clientAuth = clientAuth;
+ }
+
+ boolean isEnabled() {
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ String s = cipherSuite + " in " + protocol + " mode";
+ if (clientAuth != null) {
+ s += " with " + clientAuth + " client authentication";
+ }
+ return s;
+ }
+ }
+
+ private static volatile CipherTestUtils instnace = null;
+
+ public static CipherTestUtils getInstance() throws IOException,
+ FileNotFoundException, KeyStoreException,
+ NoSuchAlgorithmException, CertificateException,
+ UnrecoverableKeyException, InvalidKeySpecException {
+ if (instnace == null) {
+ synchronized (CipherTestUtils.class) {
+ if (instnace == null) {
+ instnace = new CipherTestUtils();
+ }
+ }
+ }
+ return instnace;
+ }
+
+ public static void setTestedArguments(String testedProtocol,
+ String testedCipherSuite) {
+
+ TestParameters testedParams;
+
+ String cipherSuite = testedCipherSuite.trim();
+ if (cipherSuite.startsWith("SSL_")) {
+ testedParams =
+ new TestParameters(cipherSuite, testedProtocol, null);
+ TESTS.add(testedParams);
+
+ } else {
+ System.out.println("Your input Cipher suites is not correct, "
+ + "please try another one .");
+ }
+ }
+
+ public X509ExtendedKeyManager getClientKeyManager() {
+ return clientKeyManager;
+ }
+
+ public X509TrustManager getClientTrustManager() {
+ return clientTrustManager;
+ }
+
+ public X509ExtendedKeyManager getServerKeyManager() {
+ return serverKeyManager;
+ }
+
+ public X509TrustManager getServerTrustManager() {
+ return serverTrustManager;
+ }
+
+ public static void addFailure(Exception e) {
+ EXCEPTIONS.add(e);
+ }
+
+ private CipherTestUtils()
+ throws IOException, FileNotFoundException, KeyStoreException,
+ NoSuchAlgorithmException, CertificateException,
+ UnrecoverableKeyException, InvalidKeySpecException {
+ factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ KeyStore serverKeyStore = createServerKeyStore(SERVER_PUBLIC_KEY,
+ SERVER_PRIVATE_KEY);
+ KeyStore serverTrustStore = createServerKeyStore(CA_PUBLIC_KEY,
+ CA_PRIVATE_KEY);
+
+ if (serverKeyStore != null) {
+ KeyManagerFactory keyFactory1
+ = KeyManagerFactory.getInstance(
+ KeyManagerFactory.getDefaultAlgorithm());
+ keyFactory1.init(serverKeyStore, PASSWORD);
+ serverKeyManager = (X509ExtendedKeyManager) keyFactory1.
+ getKeyManagers()[0];
+ } else {
+ serverKeyManager = null;
+ }
+ serverTrustManager = serverTrustStore != null
+ ? new AlwaysTrustManager(serverTrustStore) : null;
+
+ KeyStore clientKeyStore, clientTrustStore;
+ clientTrustStore = serverTrustStore;
+ clientKeyStore =
+ createServerKeyStore(CLIENT_PUBLIC_KEY,CLIENT_PRIVATE_KEY);
+ if (clientKeyStore != null) {
+ KeyManagerFactory keyFactory
+ = KeyManagerFactory.getInstance(
+ KeyManagerFactory.getDefaultAlgorithm());
+ keyFactory.init(clientKeyStore, PASSWORD);
+ clientKeyManager = (X509ExtendedKeyManager) keyFactory.
+ getKeyManagers()[0];
+ } else {
+ clientKeyManager = null;
+ }
+ clientTrustManager = (clientTrustStore != null)
+ ? new AlwaysTrustManager(clientTrustStore) : null;
+ }
+
+ void checkResult(String exception) throws Exception {
+ if (EXCEPTIONS.size() >= 1) {
+ Exception actualException = EXCEPTIONS.get(0);
+ if (exception == null) {
+ throw new RuntimeException("FAILED: got unexpected exception: "
+ + actualException);
+ }
+ if (!exception.equals(actualException.getClass().getName())) {
+ throw new RuntimeException("FAILED: got unexpected exception: "
+ + actualException);
+ }
+
+ System.out.println("PASSED: got expected exception: "
+ + actualException);
+ } else {
+ if (exception != null) {
+ throw new RuntimeException("FAILED: " + exception
+ + " was expected");
+ }
+ System.out.println("PASSED");
+ }
+ }
+
+ SSLSocketFactory getFactory() {
+ return factory;
+ }
+
+ static abstract class Client implements Runnable {
+
+ final CipherTestUtils cipherTest;
+ TestParameters testedParams;
+
+ Client(CipherTestUtils cipherTest) throws Exception {
+ this.cipherTest = cipherTest;
+ }
+
+ Client(CipherTestUtils cipherTest,
+ String testedCipherSuite) throws Exception {
+ this.cipherTest = cipherTest;
+ }
+
+ @Override
+ public final void run() {
+
+ TESTS.stream().map((params) -> {
+ if (!params.isEnabled()) {
+ System.out.println("Skipping disabled test " + params);
+ }
+ return params;
+ }).forEach((params) -> {
+ try {
+ runTest(params);
+ System.out.println("Passed " + params);
+ } catch (Exception e) {
+ CipherTestUtils.addFailure(e);
+ System.out.println("** Failed " + params
+ + "**, got exception:");
+ e.printStackTrace(System.err);
+ }
+ });
+ }
+
+ abstract void runTest(TestParameters params) throws Exception;
+
+ void sendRequest(InputStream in, OutputStream out) throws IOException {
+ out.write("GET / HTTP/1.0\r\n\r\n".getBytes());
+ out.flush();
+ StringBuilder sb = new StringBuilder();
+ while (true) {
+ int ch = in.read();
+ if (ch < 0) {
+ break;
+ }
+ sb.append((char) ch);
+ }
+ String response = sb.toString();
+ if (response.startsWith("HTTP/1.0 200 ") == false) {
+ throw new IOException("Invalid response: " + response);
+ } else {
+ System.out.println();
+ System.out.println("--- Response --- ");
+ System.out.println(response);
+ System.out.println("---------------- ");
+ }
+ }
+ }
+
+ public static void printStringArray(String[] stringArray) {
+ System.out.print(stringArray.length + " : ");
+ for (String stringArray1 : stringArray) {
+ System.out.print(stringArray1);
+ System.out.print(",");
+ }
+ System.out.println();
+ }
+
+ public static void printInfo(SSLServerSocket socket) {
+ System.out.println();
+ System.out.println("--- SSL ServerSocket Info ---");
+ System.out.print("SupportedProtocols : ");
+ printStringArray(socket.getSupportedProtocols());
+ System.out.print("SupportedCipherSuites : ");
+ printStringArray(socket.getSupportedCipherSuites());
+ System.out.print("EnabledProtocols : ");
+ printStringArray(socket.getEnabledProtocols());
+ System.out.print("EnabledCipherSuites : ");
+ String[] supportedCipherSuites = socket.getEnabledCipherSuites();
+ Arrays.sort(supportedCipherSuites);
+ printStringArray(supportedCipherSuites);
+ System.out.println("NeedClientAuth : "
+ + socket.getNeedClientAuth());
+ System.out.println("WantClientAuth : "
+ + socket.getWantClientAuth());
+ System.out.println("-----------------------");
+ }
+
+ public static void printInfo(SSLSocket socket) {
+ System.out.println();
+ System.out.println("--- SSL Socket Info ---");
+ System.out.print(" SupportedProtocols : ");
+ printStringArray(socket.getSupportedProtocols());
+ System.out.println(" EnabledProtocols : "
+ + socket.getEnabledProtocols()[0]);
+ System.out.print(" SupportedCipherSuites : ");
+ String[] supportedCipherSuites = socket.getEnabledCipherSuites();
+ Arrays.sort(supportedCipherSuites);
+ printStringArray(supportedCipherSuites);
+ System.out.println(" EnabledCipherSuites : "
+ + socket.getEnabledCipherSuites()[0]);
+ System.out.println(" NeedClientAuth : "
+ + socket.getNeedClientAuth());
+ System.out.println(" WantClientAuth : "
+ + socket.getWantClientAuth());
+ System.out.println("-----------------------");
+ }
+
+ private static KeyStore createServerKeyStore(String publicKeyStr,
+ String keySpecStr) throws KeyStoreException, IOException,
+ NoSuchAlgorithmException, CertificateException,
+ InvalidKeySpecException {
+
+ KeyStore ks = KeyStore.getInstance("JKS");
+ ks.load(null, null);
+ if (publicKeyStr == null || keySpecStr == null) {
+ throw new IllegalArgumentException("publicKeyStr or "
+ + "keySpecStr cannot be null");
+ }
+ String strippedPrivateKey = keySpecStr.substring(
+ keySpecStr.indexOf("\n"), keySpecStr.lastIndexOf("\n"));
+
+ // generate the private key.
+ PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+ Base64.getMimeDecoder().decode(strippedPrivateKey));
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKey priKey
+ = (RSAPrivateKey) kf.generatePrivate(priKeySpec);
+
+ // generate certificate chain
+ try (InputStream is =
+ new ByteArrayInputStream(publicKeyStr.getBytes())) {
+ // generate certificate from cert string
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ Certificate keyCert = cf.generateCertificate(is);
+ Certificate[] chain = {keyCert};
+ ks.setKeyEntry("TestEntry", priKey, PASSWORD, chain);
+ }
+
+ return ks;
+ }
+
+ public static void main(PeerFactory peerFactory, String mode,
+ String expectedException)
+ throws Exception {
+ long time = System.currentTimeMillis();
+ setTestedArguments(peerFactory.getTestedProtocol(),
+ peerFactory.getTestedCipher());
+
+ System.out.print(
+ " Initializing test '" + peerFactory.getName() + "'...");
+ secureRandom.nextInt();
+
+ CipherTestUtils cipherTest = CipherTestUtils.getInstance();
+ if (mode.equalsIgnoreCase("Server")) { // server mode
+ Thread serverThread = new Thread(peerFactory.newServer(cipherTest),
+ "Server");
+ serverThread.start();
+ } else if (mode.equalsIgnoreCase("Client")) {
+ peerFactory.newClient(cipherTest).run();
+ cipherTest.checkResult(expectedException);
+ JSSEServer.closeServer = true;
+ } else {
+ throw new RuntimeException("unsupported mode");
+ }
+ time = System.currentTimeMillis() - time;
+ System.out.println("Elapsed time " + time);
+
+ }
+
+ public static abstract class PeerFactory {
+
+ abstract String getName();
+
+ abstract String getTestedProtocol();
+
+ abstract String getTestedCipher();
+
+ abstract Client newClient(CipherTestUtils cipherTest) throws Exception;
+
+ abstract Server newServer(CipherTestUtils cipherTest) throws Exception;
+
+ boolean isSupported(String cipherSuite) {
+ return true;
+ }
+ }
+}
+
+class AlwaysTrustManager implements X509TrustManager {
+
+ X509TrustManager trustManager;
+
+ public AlwaysTrustManager(KeyStore keyStore)
+ throws NoSuchAlgorithmException, KeyStoreException {
+
+ TrustManagerFactory tmf
+ = TrustManagerFactory.getInstance(TrustManagerFactory.
+ getDefaultAlgorithm());
+ tmf.init(keyStore);
+
+ TrustManager tms[] = tmf.getTrustManagers();
+ for (TrustManager tm : tms) {
+ trustManager = (X509TrustManager) tm;
+ return;
+ }
+
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ try {
+ trustManager.checkClientTrusted(chain, authType);
+ } catch (CertificateException excep) {
+ System.out.println("ERROR in client trust manager");
+ }
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ try {
+ trustManager.checkServerTrusted(chain, authType);
+ } catch (CertificateException excep) {
+ System.out.println("ERROR in server Trust manger");
+ }
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return trustManager.getAcceptedIssuers();
+ }
+}
+
+class MyX509KeyManager extends X509ExtendedKeyManager {
+
+ private final X509ExtendedKeyManager keyManager;
+ private String authType;
+
+ MyX509KeyManager(X509ExtendedKeyManager keyManager) {
+ this.keyManager = keyManager;
+ }
+
+ void setAuthType(String authType) {
+ this.authType = "ECDSA".equals(authType) ? "EC" : authType;
+ }
+
+ @Override
+ public String[] getClientAliases(String keyType, Principal[] issuers) {
+ if (authType == null) {
+ return null;
+ }
+ return keyManager.getClientAliases(authType, issuers);
+ }
+
+ @Override
+ public String chooseClientAlias(String[] keyType, Principal[] issuers,
+ Socket socket) {
+ if (authType == null) {
+ return null;
+ }
+ return keyManager.chooseClientAlias(new String[]{authType},
+ issuers, socket);
+ }
+
+ @Override
+ public String chooseEngineClientAlias(String[] keyType,
+ Principal[] issuers, SSLEngine engine) {
+ if (authType == null) {
+ return null;
+ }
+ return keyManager.chooseEngineClientAlias(new String[]{authType},
+ issuers, engine);
+ }
+
+ @Override
+ public String[] getServerAliases(String keyType, Principal[] issuers) {
+ throw new UnsupportedOperationException("Servers not supported");
+ }
+
+ @Override
+ public String chooseServerAlias(String keyType, Principal[] issuers,
+ Socket socket) {
+ throw new UnsupportedOperationException("Servers not supported");
+ }
+
+ @Override
+ public String chooseEngineServerAlias(String keyType, Principal[] issuers,
+ SSLEngine engine) {
+ throw new UnsupportedOperationException("Servers not supported");
+ }
+
+ @Override
+ public X509Certificate[] getCertificateChain(String alias) {
+ return keyManager.getCertificateChain(alias);
+ }
+
+ @Override
+ public PrivateKey getPrivateKey(String alias) {
+ return keyManager.getPrivateKey(alias);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/TLS/JSSEClient.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,120 @@
+/**
+ * Copyright (c) 2010, 2014, 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.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.Certificate;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+class JSSEClient extends CipherTestUtils.Client {
+
+ private static final String DEFAULT = "DEFAULT";
+ private static final String TLS = "TLS";
+
+ private final SSLContext sslContext;
+ private final MyX509KeyManager keyManager;
+ private final int serverPort;
+ private final String serverHost;
+ private final String testedProtocol;
+
+ JSSEClient(CipherTestUtils cipherTest, String serverHost, int serverPort,
+ String testedProtocols, String testedCipherSuite) throws Exception {
+ super(cipherTest, testedCipherSuite);
+ this.serverHost = serverHost;
+ this.serverPort = serverPort;
+ this.testedProtocol = testedProtocols;
+ this.keyManager =
+ new MyX509KeyManager(cipherTest.getClientKeyManager());
+ sslContext = SSLContext.getInstance(TLS);
+ }
+
+ @Override
+ void runTest(CipherTestUtils.TestParameters params) throws Exception {
+ SSLSocket socket = null;
+ try {
+ System.out.println("Connecting to server...");
+ keyManager.setAuthType(params.clientAuth);
+ sslContext.init(new KeyManager[]{keyManager},
+ new TrustManager[]{cipherTest.getClientTrustManager()},
+ CipherTestUtils.secureRandom);
+ SSLSocketFactory factory = (SSLSocketFactory) sslContext.
+ getSocketFactory();
+ socket = (SSLSocket) factory.createSocket(serverHost,
+ serverPort);
+ socket.setSoTimeout(CipherTestUtils.TIMEOUT);
+ socket.setEnabledCipherSuites(params.cipherSuite.split(","));
+ if (params.protocol != null && !params.protocol.trim().equals("")
+ && !params.protocol.trim().equals(DEFAULT)) {
+ socket.setEnabledProtocols(params.protocol.split(","));
+ }
+ CipherTestUtils.printInfo(socket);
+ InputStream in = socket.getInputStream();
+ OutputStream out = socket.getOutputStream();
+ sendRequest(in, out);
+ SSLSession session = socket.getSession();
+ session.invalidate();
+ String cipherSuite = session.getCipherSuite();
+ if (params.cipherSuite.equals(cipherSuite) == false) {
+ throw new RuntimeException("Negotiated ciphersuite mismatch: "
+ + cipherSuite + " != " + params.cipherSuite);
+ }
+ String protocol = session.getProtocol();
+ if (!DEFAULT.equals(params.protocol)
+ && !params.protocol.contains(protocol)) {
+ throw new RuntimeException("Negotiated protocol mismatch: "
+ + protocol + " != " + params.protocol);
+ }
+ if (!cipherSuite.contains("DH_anon")) {
+ session.getPeerCertificates();
+ }
+ Certificate[] certificates = session.getLocalCertificates();
+ if (params.clientAuth == null) {
+ if (certificates != null) {
+ throw new RuntimeException("Local certificates "
+ + "should be null");
+ }
+ } else {
+ if ((certificates == null) || (certificates.length == 0)) {
+ throw new RuntimeException("Certificates missing");
+ }
+ String keyAlg = certificates[0].getPublicKey().getAlgorithm();
+ if ("EC".equals(keyAlg)) {
+ keyAlg = "ECDSA";
+ }
+ if (params.clientAuth == null ? keyAlg != null
+ : !params.clientAuth.equals(keyAlg)) {
+ throw new RuntimeException("Certificate type mismatch: "
+ + keyAlg + " != " + params.clientAuth);
+ }
+ }
+ } finally {
+ if (socket != null) {
+ socket.close();
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/TLS/JSSEServer.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2010, 2014, 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.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.TrustManager;
+
+public class JSSEServer extends CipherTestUtils.Server {
+
+ private final SSLServerSocket serverSocket;
+ private final int serverPort;
+ static volatile boolean closeServer = false;
+
+ JSSEServer(CipherTestUtils cipherTest, int serverPort,
+ String protocol, String cipherSuite) throws Exception {
+ super(cipherTest);
+ this.serverPort = serverPort;
+ SSLContext serverContext = SSLContext.getInstance("TLS");
+ serverContext.init(new KeyManager[]{cipherTest.getServerKeyManager()},
+ new TrustManager[]{cipherTest.getServerTrustManager()},
+ CipherTestUtils.secureRandom);
+ SSLServerSocketFactory factory =
+ (SSLServerSocketFactory)serverContext.getServerSocketFactory();
+ serverSocket =
+ (SSLServerSocket) factory.createServerSocket(serverPort);
+ serverSocket.setEnabledProtocols(protocol.split(","));
+ serverSocket.setEnabledCipherSuites(cipherSuite.split(","));
+
+ CipherTestUtils.printInfo(serverSocket);
+ }
+
+ @Override
+ public void run() {
+ System.out.println("JSSE Server listening on port " + serverPort);
+ while (!closeServer) {
+ try (final SSLSocket socket = (SSLSocket) serverSocket.accept()) {
+ socket.setSoTimeout(CipherTestUtils.TIMEOUT);
+
+ try (InputStream in = socket.getInputStream();
+ OutputStream out = socket.getOutputStream()) {
+ handleRequest(in, out);
+ out.flush();
+ } catch (IOException e) {
+ CipherTestUtils.addFailure(e);
+ System.out.println("Got IOException:");
+ e.printStackTrace(System.err);
+ }
+ } catch (Exception e) {
+ CipherTestUtils.addFailure(e);
+ System.out.println("Exception:");
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/TLS/TestJSSE.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,184 @@
+/**
+ * Copyright (c) 2010, 2014, 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 static java.lang.System.out;
+import java.security.Provider;
+import java.security.Security;
+
+/**
+ * @test
+ * @bug 8049429
+ * @library ../../../../lib/testlibrary/
+ * @build jdk.testlibrary.Utils
+ * @compile CipherTestUtils.java JSSEClient.java JSSEServer.java
+ * @summary Test that all cipher suites work in all versions and all client
+ * authentication types. The way this is setup the server is stateless and
+ * all checking is done on the client side.
+ * @run main/othervm -DSERVER_PROTOCOL=SSLv3
+ * -DCLIENT_PROTOCOL=SSLv3
+ * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 TestJSSE
+ * @run main/othervm -DSERVER_PROTOCOL=TLSv1
+ * -DCLIENT_PROTOCOL=SSLv3,TLSv1,TLSv1.1,TLSv1.2
+ * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 TestJSSE
+ * @run main/othervm -DSERVER_PROTOCOL=TLSv1.1
+ * -DCLIENT_PROTOCOL=SSLv3,TLSv1,TLSv1.1,TLSv1.2
+ * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 TestJSSE
+ * @run main/othervm -DSERVER_PROTOCOL=TLSv1.2
+ * -DCLIENT_PROTOCOL=SSLv3,TLSv1,TLSv1.1,TLSv1.2
+ * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 TestJSSE
+ * @run main/othervm -DSERVER_PROTOCOL=SSLv3,TLSv1
+ * -DCLIENT_PROTOCOL=TLSv1 -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 TestJSSE
+ * @run main/othervm -DSERVER_PROTOCOL=SSLv3,TLSv1,TLSv1.1
+ * -DCLIENT_PROTOCOL=TLSv1.1 -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 TestJSSE
+ * @run main/othervm -DSERVER_PROTOCOL=SSLv3
+ * -DCLIENT_PROTOCOL=TLSv1.1,TLSv1.2
+ * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5
+ * TestJSSE javax.net.ssl.SSLHandshakeException
+ * @run main/othervm -DSERVER_PROTOCOL=TLSv1
+ * -DCLIENT_PROTOCOL=TLSv1.1,TLSv1.2
+ * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5
+ * TestJSSE javax.net.ssl.SSLHandshakeException
+ * @run main/othervm -DSERVER_PROTOCOL=SSLv3,TLSv1,TLSv1.1,TLSv1.2
+ * -DCLIENT_PROTOCOL=TLSv1.2 -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 TestJSSE
+ * @run main/othervm -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1
+ * -DCLIENT_PROTOCOL=DEFAULT -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 TestJSSE
+ * @run main/othervm -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2
+ * -DCLIENT_PROTOCOL=DEFAULT -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 TestJSSE
+ * @run main/othervm -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2
+ * -DCLIENT_PROTOCOL=DEFAULT -Djdk.tls.client.protocols=TLSv1
+ * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5 TestJSSE
+ * @run main/othervm -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1
+ * -DCLIENT_PROTOCOL=DEFAULT -Djdk.tls.client.protocols=TLSv1.2
+ * -DCIPHER=SSL_RSA_WITH_RC4_128_MD5
+ * TestJSSE javax.net.ssl.SSLHandshakeException
+ *
+ */
+
+public class TestJSSE {
+
+ private static final String LOCAL_IP = "127.0.0.1";
+
+ public static void main(String... args) throws Exception {
+ String serverProtocol = System.getProperty("SERVER_PROTOCOL");
+ String clientProtocol = System.getProperty("CLIENT_PROTOCOL");
+ int port = jdk.testlibrary.Utils.getFreePort();
+ String cipher = System.getProperty("CIPHER");
+ if (serverProtocol == null
+ || clientProtocol == null
+ || cipher == null) {
+ throw new IllegalArgumentException("SERVER_PROTOCOL "
+ + "or CLIENT_PROTOCOL or CIPHER is missing");
+ }
+ out.println("ServerProtocol =" + serverProtocol);
+ out.println("ClientProtocol =" + clientProtocol);
+ out.println("Cipher =" + cipher);
+ server(serverProtocol, cipher, port, args);
+ client(port, clientProtocol, cipher, args);
+
+ }
+
+ public static void client(int testPort,
+ String testProtocols, String testCipher,
+ String... exception) throws Exception {
+ String expectedException = exception.length >= 1
+ ? exception[0] : null;
+ out.println("=========================================");
+ out.println(" Testing - https://" + LOCAL_IP + ":" + testPort);
+ out.println(" Testing - Protocol : " + testProtocols);
+ out.println(" Testing - Cipher : " + testCipher);
+ Provider p = new sun.security.ec.SunEC();
+ Security.insertProviderAt(p, 1);
+ try {
+ CipherTestUtils.main(new JSSEFactory(LOCAL_IP,
+ testPort, testProtocols,
+ testCipher, "client JSSE"),
+ "client", expectedException);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static void server(String testProtocol, String testCipher,
+ int testPort,
+ String... exception) throws Exception {
+ String expectedException = exception.length >= 1
+ ? exception[0] : null;
+ out.println(" This is Server");
+ out.println(" Testing Protocol: " + testProtocol);
+ out.println(" Testing Cipher: " + testCipher);
+ out.println(" Testing Port: " + testPort);
+ Provider p = new sun.security.ec.SunEC();
+ Security.insertProviderAt(p, 1);
+ try {
+ CipherTestUtils.main(new JSSEFactory(null, testPort,
+ testProtocol, testCipher, "Server JSSE"),
+ "Server", expectedException);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static class JSSEFactory extends CipherTestUtils.PeerFactory {
+
+ final String testedCipherSuite, testedProtocol, testHost;
+ final int testPort;
+ final String name;
+
+ JSSEFactory(String testHost, int testPort, String testedProtocol,
+ String testedCipherSuite, String name) {
+ this.testedCipherSuite = testedCipherSuite;
+ this.testedProtocol = testedProtocol;
+ this.testHost = testHost;
+ this.testPort = testPort;
+ this.name = name;
+ }
+
+ @Override
+ String getName() {
+ return name;
+ }
+
+ @Override
+ String getTestedCipher() {
+ return testedCipherSuite;
+ }
+
+ @Override
+ String getTestedProtocol() {
+ return testedProtocol;
+ }
+
+ @Override
+ CipherTestUtils.Client newClient(CipherTestUtils cipherTest)
+ throws Exception {
+ return new JSSEClient(cipherTest, testHost, testPort,
+ testedProtocol, testedCipherSuite);
+ }
+
+ @Override
+ CipherTestUtils.Server newServer(CipherTestUtils cipherTest)
+ throws Exception {
+ return new JSSEServer(cipherTest, testPort,
+ testedProtocol, testedCipherSuite);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/sql/testng/test/rowset/spi/SyncFactoryPermissionsTests.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2014, 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 test.rowset.spi;
+
+import java.security.AccessControlException;
+import java.security.Policy;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.sql.rowset.spi.SyncFactory;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import util.BaseTest;
+import util.TestPolicy;
+
+public class SyncFactoryPermissionsTests extends BaseTest {
+
+ Context ctx;
+ private static Policy policy;
+ private static SecurityManager sm;
+
+ /*
+ * Install a SeeurityManager along with a base Policy to allow testNG to run
+ */
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ setPolicy(new TestPolicy());
+ System.setSecurityManager(new SecurityManager());
+ }
+
+ /*
+ * Install the original Policy and SecurityManager
+ */
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ System.setSecurityManager(sm);
+ setPolicy(policy);
+ }
+
+ /*
+ * Initialize a Context to be used in our tests.
+ * Save off the original Policy and SecurityManager
+ */
+ public SyncFactoryPermissionsTests() {
+ policy = Policy.getPolicy();
+ sm = System.getSecurityManager();
+
+ try {
+ ctx = new InitialContext();
+ } catch (NamingException ex) {
+ Logger.getLogger(SyncFactoryPermissionsTests.class.getName()).
+ log(Level.SEVERE, null, ex);
+ }
+ }
+
+ /*
+ * Validate that AccessControlException is thrown if
+ * SQLPermission("setSyncFactory") has not been granted
+ */
+ @Test(expectedExceptions = AccessControlException.class)
+ public void test() throws Exception {
+ setPolicy(new TestPolicy());
+ SyncFactory.setJNDIContext(ctx);
+ }
+
+ /*
+ * Validate that setJNDIContext succeeds if SQLPermission("setSyncFactory")
+ * has been granted
+ */
+ @Test
+ public void test1() throws Exception {
+ Policy.setPolicy(new TestPolicy("setSyncFactory"));
+ SyncFactory.setJNDIContext(ctx);
+ }
+
+ /*
+ * Validate that setJNDIContext succeeds if AllPermissions has been granted
+ */
+ @Test
+ public void test2() throws Exception {
+ setPolicy(new TestPolicy("all"));
+ SyncFactory.setJNDIContext(ctx);
+ }
+}
--- a/jdk/test/javax/sql/testng/util/BaseTest.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/test/javax/sql/testng/util/BaseTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -27,6 +27,7 @@
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import java.security.Policy;
import java.sql.SQLException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
@@ -88,4 +89,11 @@
}
return o1;
}
+
+ /*
+ * Utility Method used to set the current Policy
+ */
+ protected static void setPolicy(Policy p) {
+ Policy.setPolicy(p);
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/sql/testng/util/TestPolicy.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2014, 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 util;
+
+import java.io.FilePermission;
+import java.security.AllPermission;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import java.security.SecurityPermission;
+import java.sql.SQLPermission;
+import java.util.Enumeration;
+import java.util.PropertyPermission;
+import java.util.StringJoiner;
+
+/*
+ * Simple Policy class that supports the required Permissions to validate the
+ * JDBC concrete classes
+ */
+public class TestPolicy extends Policy {
+
+ final PermissionCollection permissions = new Permissions();
+
+ /**
+ * Constructor which sets the minimum permissions allowing testNG to work
+ * with a SecurityManager
+ */
+ public TestPolicy() {
+ setMinimalPermissions();
+ }
+
+ /*
+ * Constructor which determines which permissions are defined for this
+ * Policy used by the JDBC tests Possible values are: all (ALLPermissions),
+ * setLog (SQLPemission("setLog"), deregisterDriver
+ * (SQLPermission("deregisterDriver") (SQLPermission("deregisterDriver"),
+ * and setSyncFactory(SQLPermission(setSyncFactory),
+ *
+ * @param policy Permissions to set
+ */
+ public TestPolicy(String policy) {
+
+ switch (policy) {
+ case "all":
+ permissions.add(new AllPermission());
+ break;
+ case "setLog":
+ setMinimalPermissions();
+ permissions.add(new SQLPermission("setLog"));
+ break;
+ case "deregisterDriver":
+ setMinimalPermissions();
+ permissions.add(new SQLPermission("deregisterDriver"));
+ break;
+ case "setSyncFactory":
+ setMinimalPermissions();
+ permissions.add(new SQLPermission("setSyncFactory"));
+ break;
+ default:
+ setMinimalPermissions();
+ }
+ }
+
+ /*
+ * Defines the minimal permissions required by testNG when running these
+ * tests
+ */
+ private void setMinimalPermissions() {
+ permissions.add(new SecurityPermission("getPolicy"));
+ permissions.add(new SecurityPermission("setPolicy"));
+ permissions.add(new RuntimePermission("getClassLoader"));
+ permissions.add(new RuntimePermission("setSecurityManager"));
+ permissions.add(new RuntimePermission("createSecurityManager"));
+ permissions.add(new PropertyPermission("testng.show.stack.frames",
+ "read"));
+ permissions.add(new PropertyPermission("line.separator", "read"));
+ permissions.add(new PropertyPermission("fileStringBuffer", "read"));
+ permissions.add(new PropertyPermission("dataproviderthreadcount", "read"));
+ permissions.add(new PropertyPermission("java.io.tmpdir", "read"));
+ permissions.add(new FilePermission("<<ALL FILES>>",
+ "read, write, delete"));
+ }
+
+ /*
+ * Overloaded methods from the Policy class
+ */
+ @Override
+ public String toString() {
+ StringJoiner sj = new StringJoiner("\n", "policy: ", "");
+ Enumeration<Permission> perms = permissions.elements();
+ while (perms.hasMoreElements()) {
+ sj.add(perms.nextElement().toString());
+ }
+ return sj.toString();
+
+ }
+
+ @Override
+ public PermissionCollection getPermissions(ProtectionDomain domain) {
+ return permissions;
+ }
+
+ @Override
+ public PermissionCollection getPermissions(CodeSource codesource) {
+ return permissions;
+ }
+
+ @Override
+ public boolean implies(ProtectionDomain domain, Permission perm) {
+ return permissions.implies(perm);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/BaseTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,338 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.File;
+import java.net.URL;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.validation.Validator;
+
+
+import com.sun.org.apache.xerces.internal.dom.PSVIElementNSImpl;
+import com.sun.org.apache.xerces.internal.impl.Constants;
+import com.sun.org.apache.xerces.internal.impl.xs.SchemaGrammar;
+import com.sun.org.apache.xerces.internal.xs.ElementPSVI;
+import com.sun.org.apache.xerces.internal.xs.ItemPSVI;
+import com.sun.org.apache.xerces.internal.xs.XSElementDeclaration;
+import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
+import javax.xml.transform.stream.StreamSource;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+public abstract class BaseTest {
+ protected final static String ROOT_TYPE = Constants.XERCES_PROPERTY_PREFIX
+ + Constants.ROOT_TYPE_DEFINITION_PROPERTY;
+
+ protected final static String IGNORE_XSI_TYPE = Constants.XERCES_FEATURE_PREFIX
+ + Constants.IGNORE_XSI_TYPE_FEATURE;
+
+ protected final static String ID_IDREF_CHECKING = Constants.XERCES_FEATURE_PREFIX
+ + Constants.ID_IDREF_CHECKING_FEATURE;
+
+ protected final static String IDC_CHECKING = Constants.XERCES_FEATURE_PREFIX
+ + Constants.IDC_CHECKING_FEATURE;
+
+ protected final static String UNPARSED_ENTITY_CHECKING = Constants.XERCES_FEATURE_PREFIX
+ + Constants.UNPARSED_ENTITY_CHECKING_FEATURE;
+
+ protected final static String USE_GRAMMAR_POOL_ONLY = Constants.XERCES_FEATURE_PREFIX
+ + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE;
+
+ protected final static String DYNAMIC_VALIDATION = Constants.XERCES_FEATURE_PREFIX
+ + Constants.DYNAMIC_VALIDATION_FEATURE;
+
+ protected final static String DOCUMENT_CLASS_NAME = Constants.XERCES_PROPERTY_PREFIX
+ + Constants.DOCUMENT_CLASS_NAME_PROPERTY;
+
+ protected Schema schema;
+ protected Validator fValidator;
+
+ protected SpecialCaseErrorHandler fErrorHandler;
+
+ DocumentBuilder builder;
+ protected Document fDocument;
+
+ protected ElementPSVI fRootNode;
+
+ protected URL fDocumentURL;
+ protected String documentPath;
+ protected String fDocumentId;
+
+ static String errMessage;
+
+ int passed = 0, failed = 0;
+
+ public static boolean isWindows = false;
+ static {
+ if (System.getProperty("os.name").indexOf("Windows")>-1) {
+ isWindows = true;
+ }
+ };
+ public static final String USER_DIR = System.getProperty("user.dir", ".");
+ public static final String BASE_DIR = System.getProperty("test.src", USER_DIR)
+ .replaceAll("\\" + System.getProperty("file.separator"), "/");
+
+ protected abstract String getSchemaFile();
+
+ protected abstract String getXMLDocument();
+
+ public BaseTest(String name) {
+ fErrorHandler = new SpecialCaseErrorHandler(getRelevantErrorIDs());
+ }
+
+ protected void setUp() throws Exception {
+
+ DocumentBuilderFactory docFactory = DocumentBuilderFactory
+ .newInstance();
+ docFactory.setAttribute(DOCUMENT_CLASS_NAME,
+ "com.sun.org.apache.xerces.internal.dom.PSVIDocumentImpl");
+ docFactory.setNamespaceAware(true);
+ builder = docFactory.newDocumentBuilder();
+
+ documentPath = BASE_DIR + "/" + getXMLDocument();
+System.out.println("documentPath:"+documentPath);
+ if (isWindows) {
+ fDocumentId = "file:/" + documentPath;
+ } else {
+ fDocumentId = "file:" + documentPath;
+ }
+ //fDocumentURL = ClassLoader.getSystemResource(documentPath);
+ //fDocumentURL = getClass().getResource(documentPath);
+System.out.println("fDocumentId:"+fDocumentId);
+//System.out.println("fDocumentURL.toExternalForm:"+fDocumentURL.toExternalForm());
+/**
+ if (fDocumentURL == null) {
+ throw new FileNotFoundException("Couldn't find xml file for test: " + documentPath);
+ }
+ fDocument = builder.parse(fDocumentURL.toExternalForm());
+ fRootNode = (ElementPSVI) fDocument.getDocumentElement();
+ */
+ SchemaFactory sf = SchemaFactory
+ .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+ sf.setFeature(USE_GRAMMAR_POOL_ONLY, getUseGrammarPoolOnly());
+ String schemaPath = BASE_DIR + "/" + getSchemaFile();
+ /**
+ URL schemaURL = ClassLoader.getSystemResource(schemaPath);
+ if (schemaURL == null) {
+ throw new FileNotFoundException("Couldn't find schema file for test: " + schemaPath);
+ }
+ */
+ schema = sf.newSchema(new StreamSource(new File(schemaPath)));
+ }
+
+ protected void tearDown() throws Exception {
+ fValidator = null;
+ fDocument = null;
+ fRootNode = null;
+ fErrorHandler.reset();
+ System.out.println("\nNumber of tests passed: " + passed);
+ System.out.println("Number of tests failed: " + failed + "\n");
+
+ if (errMessage != null) {
+ throw new RuntimeException(errMessage);
+ }
+ }
+
+ protected void validateDocument() throws Exception {
+ Source source = new DOMSource(fDocument);
+ source.setSystemId(fDocumentId);
+ Result result = new DOMResult(fDocument);
+ fValidator.validate(source, result);
+ }
+
+ protected void validateFragment() throws Exception {
+ Source source = new DOMSource((Node) fRootNode);
+ source.setSystemId(fDocumentId);
+ Result result = new DOMResult((Node) fRootNode);
+ fValidator.validate(source, result);
+ }
+
+ protected void reset() throws Exception {
+ try {
+System.out.println("new File(documentPath)" + new File(documentPath));
+
+ fDocument = builder.parse(new File(documentPath));
+ fRootNode = (ElementPSVI) fDocument.getDocumentElement();
+System.out.println("fDocument" + fDocument);
+System.out.println("fRootNode" + fRootNode);
+ fValidator = schema.newValidator();
+ fErrorHandler.reset();
+ fValidator.setErrorHandler(fErrorHandler);
+ fValidator.setFeature(DYNAMIC_VALIDATION, false);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ protected PSVIElementNSImpl getChild(int n) {
+ int numFound = 0;
+ Node child = ((Node) fRootNode).getFirstChild();
+ while (child != null) {
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ numFound++;
+ if (numFound == n) {
+ return (PSVIElementNSImpl) child;
+ }
+ }
+ child = child.getNextSibling();
+ }
+ return null;
+ }
+
+ protected String[] getRelevantErrorIDs() {
+ return new String[] {};
+ }
+
+ protected boolean getUseGrammarPoolOnly() {
+ return false;
+ }
+
+ // specialized asserts
+
+ protected void assertValidity(short expectedValidity, short actualValidity) {
+ String expectedString = expectedValidity == ItemPSVI.VALIDITY_VALID ? "valid"
+ : (expectedValidity == ItemPSVI.VALIDITY_INVALID ? "invalid"
+ : "notKnown");
+ String actualString = actualValidity == ItemPSVI.VALIDITY_VALID ? "valid"
+ : (actualValidity == ItemPSVI.VALIDITY_INVALID ? "invalid"
+ : "notKnown");
+ String message = "{validity} was <" + actualString
+ + "> but it should have been <" + expectedString + ">";
+ assertEquals(message, expectedValidity, actualValidity);
+ }
+
+ protected void assertValidationAttempted(short expectedAttempted,
+ short actualAttempted) {
+ String expectedString = expectedAttempted == ItemPSVI.VALIDATION_FULL ? "full"
+ : (expectedAttempted == ItemPSVI.VALIDATION_PARTIAL ? "partial"
+ : "none");
+ String actualString = actualAttempted == ItemPSVI.VALIDATION_FULL ? "full"
+ : (actualAttempted == ItemPSVI.VALIDATION_PARTIAL ? "partial"
+ : "none");
+ String message = "{validity} was <" + actualString
+ + "> but it should have been <" + expectedString + ">";
+ assertEquals(message, expectedAttempted, actualAttempted);
+ }
+
+ protected void assertElementName(String expectedName, String actualName) {
+ assertEquals("Local name of element declaration is wrong.",
+ expectedName, actualName);
+ }
+
+ protected void assertElementNull(XSElementDeclaration elem) {
+ assertNull("Element declaration should be null.", elem);
+ }
+
+ protected void assertElementNamespace(String expectedName, String actualName) {
+ assertEquals("Namespace of element declaration is wrong.",
+ expectedName, actualName);
+ }
+
+ protected void assertElementNamespaceNull(String actualName) {
+ assertNull("Local name of element declaration should be null.",
+ actualName);
+ }
+
+ protected void assertTypeName(String expectedName, String actualName) {
+ assertEquals("Local name of type definition is wrong.", expectedName,
+ actualName);
+ }
+
+ protected void assertTypeNull(XSTypeDefinition type) {
+ assertNull("Type definition should be null.", type);
+ }
+
+ protected void assertTypeNamespace(String expectedName, String actualName) {
+ assertEquals("Namespace of type definition is wrong.", expectedName,
+ actualName);
+ }
+
+ protected void assertTypeNamespaceNull(String actualName) {
+ assertNull("Namespace of type definition should be null.", actualName);
+ }
+
+ protected void assertError(String error) {
+ assertTrue("Error <" + error + "> should have occured, but did not.",
+ fErrorHandler.specialCaseFound(error));
+ }
+
+ protected void assertNoError(String error) {
+ assertFalse("Error <" + error
+ + "> should not have occured (but it did)", fErrorHandler
+ .specialCaseFound(error));
+ }
+
+ protected void assertAnyType(XSTypeDefinition type) {
+ assertEquals("Type is supposed to be anyType", SchemaGrammar.fAnyType,
+ type);
+ }
+
+ void assertEquals(String msg, Object expected, Object actual) {
+ if (!expected.equals(actual)) {
+ fail(msg + " Expected: " + expected + " Actual: " + actual);
+ } else {
+ success(null);
+ }
+ }
+ void assertNull(String msg, Object value) {
+ if (value != null) {
+ fail(msg);
+ } else {
+ success(null);
+ }
+ }
+ void assertTrue(String msg, boolean value) {
+ if (!value) {
+ fail(msg);
+ } else {
+ success(null);
+ }
+ }
+ void assertFalse(String msg, boolean value) {
+ if (value) {
+ fail(msg);
+ } else {
+ success(null);
+ }
+ }
+ void fail(String errMsg) {
+ if (errMessage == null) {
+ errMessage = errMsg;
+ } else {
+ errMessage = errMessage + "\n" + errMsg;
+ }
+ failed++;
+ }
+
+ void success(String msg) {
+ passed++;
+ System.out.println(msg);
+ if (msg != null) {
+ if (msg.length() != 0) {
+ System.out.println(msg);
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/BasicTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.sun.org.apache.xerces.internal.dom.PSVIElementNSImpl;
+import com.sun.org.apache.xerces.internal.xs.ItemPSVI;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class BasicTest extends BaseTest {
+
+ protected String getXMLDocument() {
+ return "base.xml";
+ }
+
+ protected String getSchemaFile() {
+ return "base.xsd";
+ }
+
+ public BasicTest(String name) {
+ super(name);
+ }
+
+ @BeforeClass
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @AfterClass
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testSimpleValidation() {
+ try {
+ reset();
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+ doValidityAsserts();
+ }
+
+ @Test
+ public void testSimpleValidationWithTrivialXSIType() {
+ try {
+ reset();
+ ((PSVIElementNSImpl) fRootNode).setAttributeNS(
+ "http://www.w3.org/2001/XMLSchema-instance", "type", "X");
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+ doValidityAsserts();
+ }
+
+ private void doValidityAsserts() {
+ assertValidity(ItemPSVI.VALIDITY_VALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementName("A", fRootNode.getElementDeclaration().getName());
+ assertElementNamespaceNull(fRootNode.getElementDeclaration()
+ .getNamespace());
+ assertTypeName("X", fRootNode.getTypeDefinition().getName());
+ assertTypeNamespaceNull(fRootNode.getTypeDefinition().getNamespace());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/FixedAttrTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.sun.org.apache.xerces.internal.dom.PSVIElementNSImpl;
+import com.sun.org.apache.xerces.internal.xs.ItemPSVI;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * The purpose of this test is to execute all of the isComparable calls in
+ * XMLSchemaValidator. There are two calls in processElementContent and two
+ * calls in processOneAttribute.
+ *
+ * @author peterjm
+ */
+public class FixedAttrTest extends BaseTest {
+
+ protected String getXMLDocument() {
+ return "fixedAttr.xml";
+ }
+
+ protected String getSchemaFile() {
+ return "base.xsd";
+ }
+
+ public FixedAttrTest(String name) {
+ super(name);
+ }
+
+ @BeforeClass
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @AfterClass
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testDefault() {
+ try {
+ reset();
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ assertValidity(ItemPSVI.VALIDITY_VALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementName("A", fRootNode.getElementDeclaration().getName());
+
+ PSVIElementNSImpl child = super.getChild(1);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("B", child.getElementDeclaration().getName());
+
+ child = super.getChild(2);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("D", child.getElementDeclaration().getName());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/IdIdrefCheckingTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.sun.org.apache.xerces.internal.dom.PSVIElementNSImpl;
+import com.sun.org.apache.xerces.internal.xs.ItemPSVI;
+import org.xml.sax.SAXException;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+// duplicate IDs
+// reference to non-existent ID
+
+public class IdIdrefCheckingTest extends BaseTest {
+ public static final String DUPLICATE_ID = "cvc-id.2";
+
+ public static final String NO_ID_BINDING = "cvc-id.1";
+
+ protected String getXMLDocument() {
+ return "idIdref.xml";
+ }
+
+ protected String getSchemaFile() {
+ return "base.xsd";
+ }
+
+ protected String[] getRelevantErrorIDs() {
+ return new String[] { DUPLICATE_ID, NO_ID_BINDING };
+ }
+
+ public IdIdrefCheckingTest(String name) {
+ super(name);
+ }
+
+ @BeforeClass
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @AfterClass
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testDefault() {
+ try {
+ reset();
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkDefault();
+ }
+
+ @Test
+ public void testSetFalse() {
+ try {
+ reset();
+ fValidator.setFeature(ID_IDREF_CHECKING, false);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkValidResult();
+ }
+
+ @Test
+ public void testSetTrue() {
+ try {
+ reset();
+ fValidator.setFeature(ID_IDREF_CHECKING, true);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkDefault();
+ }
+
+ private void checkDefault() {
+ assertError(DUPLICATE_ID);
+ assertError(NO_ID_BINDING);
+
+ assertValidity(ItemPSVI.VALIDITY_INVALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementName("A", fRootNode.getElementDeclaration().getName());
+ assertTypeName("X", fRootNode.getTypeDefinition().getName());
+
+ PSVIElementNSImpl child = super.getChild(1);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("A", child.getElementDeclaration().getName());
+ assertTypeName("idType", child.getTypeDefinition().getName());
+
+ child = super.getChild(2);
+ assertValidity(ItemPSVI.VALIDITY_INVALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("A", child.getElementDeclaration().getName());
+ assertTypeName("idType", child.getTypeDefinition().getName());
+
+ child = super.getChild(3);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("A", child.getElementDeclaration().getName());
+ assertTypeName("idrefType", child.getTypeDefinition().getName());
+ }
+
+ private void checkValidResult() {
+ assertNoError(DUPLICATE_ID);
+ assertNoError(NO_ID_BINDING);
+
+ assertValidity(ItemPSVI.VALIDITY_VALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementName("A", fRootNode.getElementDeclaration().getName());
+ assertTypeName("X", fRootNode.getTypeDefinition().getName());
+
+ PSVIElementNSImpl child = super.getChild(1);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("A", child.getElementDeclaration().getName());
+ assertTypeName("idType", child.getTypeDefinition().getName());
+
+ child = super.getChild(2);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("A", child.getElementDeclaration().getName());
+ assertTypeName("idType", child.getTypeDefinition().getName());
+
+ child = super.getChild(3);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("A", child.getElementDeclaration().getName());
+ assertTypeName("idrefType", child.getTypeDefinition().getName());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/IdentityConstraintCheckingTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.sun.org.apache.xerces.internal.dom.PSVIElementNSImpl;
+import com.sun.org.apache.xerces.internal.xs.ItemPSVI;
+import org.xml.sax.SAXException;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class IdentityConstraintCheckingTest extends BaseTest {
+ // These values are unstable, since they're not actually error keys, but
+ // simply
+ // the first part of the error message.
+ public static final String DUPLICATE_UNIQUE = "cvc-identity-constraint.4.1";
+
+ public static final String DUPLICATE_KEY = "cvc-identity-constraint.4.2.2";
+
+ public static final String INVALID_KEYREF = "cvc-identity-constraint.4.3";
+
+ protected String getXMLDocument() {
+ return "idc.xml";
+ }
+
+ protected String getSchemaFile() {
+ return "idc.xsd";
+ }
+
+ protected String[] getRelevantErrorIDs() {
+ return new String[] { DUPLICATE_UNIQUE, DUPLICATE_KEY, INVALID_KEYREF };
+ }
+
+ public IdentityConstraintCheckingTest(String name) {
+ super(name);
+ }
+
+ @BeforeClass
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @AfterClass
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testDefault() {
+ try {
+ reset();
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkDefault();
+ }
+
+ @Test
+ public void testSetFalse() {
+ try {
+ reset();
+ fValidator.setFeature(IDC_CHECKING, false);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkValidResult();
+ }
+
+ @Test
+ public void testSetTrue() {
+ try {
+ reset();
+ fValidator.setFeature(IDC_CHECKING, true);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkDefault();
+ }
+
+ private void checkDefault() {
+ assertError(DUPLICATE_UNIQUE);
+ assertError(DUPLICATE_KEY);
+ assertError(INVALID_KEYREF);
+
+ assertValidity(ItemPSVI.VALIDITY_INVALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementName("itemList", fRootNode.getElementDeclaration()
+ .getName());
+ assertTypeName("itemListType", fRootNode.getTypeDefinition().getName());
+
+ // this one is valid because it's the first one to define the unique
+ // value
+ PSVIElementNSImpl child = super.getChild(1);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("item", child.getElementDeclaration().getName());
+ assertTypeName("itemType", child.getTypeDefinition().getName());
+
+ // invalid because it repeats the unique value
+ child = super.getChild(2);
+ assertValidity(ItemPSVI.VALIDITY_INVALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("item", child.getElementDeclaration().getName());
+ assertTypeName("itemType", child.getTypeDefinition().getName());
+
+ // invalid because it repeats the key
+ child = super.getChild(3);
+ assertValidity(ItemPSVI.VALIDITY_INVALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("item", child.getElementDeclaration().getName());
+ assertTypeName("itemType", child.getTypeDefinition().getName());
+
+ // valid because key references aren't figured out until the validation
+ // root
+ child = super.getChild(4);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("itemRef", child.getElementDeclaration().getName());
+ assertTypeName("string", child.getTypeDefinition().getName());
+ }
+
+ private void checkValidResult() {
+ assertNoError(DUPLICATE_UNIQUE);
+ assertNoError(DUPLICATE_KEY);
+ assertNoError(INVALID_KEYREF);
+
+ assertValidity(ItemPSVI.VALIDITY_VALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementName("itemList", fRootNode.getElementDeclaration()
+ .getName());
+ assertTypeName("itemListType", fRootNode.getTypeDefinition().getName());
+
+ PSVIElementNSImpl child = super.getChild(1);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("item", child.getElementDeclaration().getName());
+ assertTypeName("itemType", child.getTypeDefinition().getName());
+
+ child = super.getChild(2);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("item", child.getElementDeclaration().getName());
+ assertTypeName("itemType", child.getTypeDefinition().getName());
+
+ child = super.getChild(3);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("item", child.getElementDeclaration().getName());
+ assertTypeName("itemType", child.getTypeDefinition().getName());
+
+ child = super.getChild(4);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("itemRef", child.getElementDeclaration().getName());
+ assertTypeName("string", child.getTypeDefinition().getName());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/IgnoreXSITypeTest_A_A.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+import com.sun.org.apache.xerces.internal.dom.PSVIElementNSImpl;
+import com.sun.org.apache.xerces.internal.xs.ItemPSVI;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class IgnoreXSITypeTest_A_A extends BaseTest {
+
+ protected String getXMLDocument() {
+ return "xsitype_A_A.xml";
+ }
+
+ protected String getSchemaFile() {
+ return "base.xsd";
+ }
+
+ public IgnoreXSITypeTest_A_A(String name) {
+ super(name);
+ }
+
+ @BeforeClass
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @AfterClass
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testDefaultDocument() {
+ try {
+ reset();
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ // default value of the feature is false
+ checkFalseResult();
+ }
+
+ @Test
+ public void testDefaultFragment() {
+ try {
+ reset();
+ validateFragment();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ // default value of the feature is false
+ checkFalseResult();
+ }
+
+ @Test
+ public void testSetFalseDocument() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, false);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkFalseResult();
+ }
+
+ @Test
+ public void testSetFalseFragment() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, false);
+ validateFragment();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkFalseResult();
+ }
+
+ @Test
+ public void testSetTrueDocument() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, true);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkTrueResult();
+ }
+
+ @Test
+ public void testSetTrueFragment() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, true);
+ validateFragment();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkTrueResult();
+ }
+
+ private void checkTrueResult() {
+ checkResult();
+ }
+
+ private void checkFalseResult() {
+ checkResult();
+ }
+
+ private void checkResult() {
+ assertValidity(ItemPSVI.VALIDITY_VALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementName("A", fRootNode.getElementDeclaration().getName());
+ assertTypeName("Y", fRootNode.getTypeDefinition().getName());
+ assertTypeNamespaceNull(fRootNode.getTypeDefinition().getNamespace());
+
+ PSVIElementNSImpl child = super.getChild(1);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("A", child.getElementDeclaration().getName());
+ assertTypeName("Y", child.getTypeDefinition().getName());
+ assertTypeNamespaceNull(child.getTypeDefinition().getNamespace());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/IgnoreXSITypeTest_A_C.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.sun.org.apache.xerces.internal.dom.PSVIElementNSImpl;
+import com.sun.org.apache.xerces.internal.xs.ItemPSVI;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class IgnoreXSITypeTest_A_C extends BaseTest {
+
+ protected String getXMLDocument() {
+ return "xsitype_A_C.xml";
+ }
+
+ protected String getSchemaFile() {
+ return "base.xsd";
+ }
+
+ public IgnoreXSITypeTest_A_C(String name) {
+ super(name);
+ }
+
+
+ @BeforeClass
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @AfterClass
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testDefaultDocument() {
+ try {
+ reset();
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ // default value of the feature is false
+ checkFalseResult();
+ }
+
+ @Test
+ public void testDefaultFragment() {
+ try {
+ reset();
+ validateFragment();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ // default value of the feature is false
+ checkFalseResult();
+ }
+
+ @Test
+ public void testSetFalseDocument() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, false);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkFalseResult();
+ }
+
+ @Test
+ public void testSetFalseFragment() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, false);
+ validateFragment();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkFalseResult();
+ }
+
+ @Test
+ public void testSetTrueDocument() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, true);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkTrueResult();
+ }
+
+ @Test
+ public void testSetTrueFragment() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, true);
+ validateFragment();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkTrueResult();
+ }
+
+ private void checkTrueResult() {
+ checkResult();
+ }
+
+ private void checkFalseResult() {
+ checkResult();
+ }
+
+ private void checkResult() {
+ assertValidity(ItemPSVI.VALIDITY_VALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementName("A", fRootNode.getElementDeclaration().getName());
+ assertTypeName("Y", fRootNode.getTypeDefinition().getName());
+ assertTypeNamespaceNull(fRootNode.getTypeDefinition().getNamespace());
+
+ PSVIElementNSImpl child = super.getChild(1);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementNull(child.getElementDeclaration());
+ assertTypeName("Y", child.getTypeDefinition().getName());
+ assertTypeNamespaceNull(child.getTypeDefinition().getNamespace());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/IgnoreXSITypeTest_C_A.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.sun.org.apache.xerces.internal.dom.PSVIElementNSImpl;
+import com.sun.org.apache.xerces.internal.xs.ItemPSVI;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class IgnoreXSITypeTest_C_A extends BaseTest {
+
+ protected String getXMLDocument() {
+ return "xsitype_C_A.xml";
+ }
+
+ protected String getSchemaFile() {
+ return "base.xsd";
+ }
+
+ public IgnoreXSITypeTest_C_A(String name) {
+ super(name);
+ }
+
+
+ @BeforeClass
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @AfterClass
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testDefaultDocument() {
+ try {
+ reset();
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ // default value of the feature is false
+ checkFalseResult();
+ }
+
+ @Test
+ public void testDefaultFragment() {
+ try {
+ reset();
+ validateFragment();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ // default value of the feature is false
+ checkFalseResult();
+ }
+
+ @Test
+ public void testSetFalseDocument() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, false);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkFalseResult();
+ }
+
+ @Test
+ public void testSetFalseFragment() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, false);
+ validateFragment();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkFalseResult();
+ }
+
+ @Test
+ public void testSetTrueDocument() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, true);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkTrueResult();
+ }
+
+ @Test
+ public void testSetTrueFragment() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, true);
+ validateFragment();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkTrueResult();
+ }
+
+ private void checkTrueResult() {
+ assertValidity(ItemPSVI.VALIDITY_NOTKNOWN, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_PARTIAL, fRootNode
+ .getValidationAttempted());
+ assertElementNull(fRootNode.getElementDeclaration());
+ assertAnyType(fRootNode.getTypeDefinition());
+
+ checkChild();
+ }
+
+ private void checkFalseResult() {
+ assertValidity(ItemPSVI.VALIDITY_VALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementNull(fRootNode.getElementDeclaration());
+ assertTypeName("Y", fRootNode.getTypeDefinition().getName());
+ assertTypeNamespaceNull(fRootNode.getTypeDefinition().getNamespace());
+
+ checkChild();
+ }
+
+ private void checkChild() {
+ PSVIElementNSImpl child = super.getChild(1);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("A", child.getElementDeclaration().getName());
+ assertTypeName("Y", child.getTypeDefinition().getName());
+ assertTypeNamespaceNull(child.getTypeDefinition().getNamespace());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/IgnoreXSITypeTest_C_AC.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,174 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.sun.org.apache.xerces.internal.dom.PSVIElementNSImpl;
+import com.sun.org.apache.xerces.internal.xs.ItemPSVI;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class IgnoreXSITypeTest_C_AC extends BaseTest {
+
+ protected String getXMLDocument() {
+ return "xsitype_C_AC.xml";
+ }
+
+ protected String getSchemaFile() {
+ return "base.xsd";
+ }
+
+ public IgnoreXSITypeTest_C_AC(String name) {
+ super(name);
+ }
+
+
+ @BeforeClass
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @AfterClass
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testDefaultDocument() {
+ try {
+ reset();
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ // default value of the feature is false
+ checkFalseResult();
+ }
+
+ @Test
+ public void testDefaultFragment() {
+ try {
+ reset();
+ validateFragment();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ // default value of the feature is false
+ checkFalseResult();
+ }
+
+ @Test
+ public void testSetFalseDocument() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, false);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkFalseResult();
+ }
+
+ @Test
+ public void testSetFalseFragment() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, false);
+ validateFragment();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkFalseResult();
+ }
+
+ @Test
+ public void testSetTrueDocument() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, true);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkTrueResult();
+ }
+
+ @Test
+ public void testSetTrueFragment() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, true);
+ validateFragment();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkTrueResult();
+ }
+
+ private void checkTrueResult() {
+ assertValidity(ItemPSVI.VALIDITY_NOTKNOWN, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_PARTIAL, fRootNode
+ .getValidationAttempted());
+ assertElementNull(fRootNode.getElementDeclaration());
+ assertAnyType(fRootNode.getTypeDefinition());
+
+ PSVIElementNSImpl child = super.getChild(1);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("A", child.getElementDeclaration().getName());
+ assertTypeName("Y", child.getTypeDefinition().getName());
+ assertTypeNamespaceNull(child.getTypeDefinition().getNamespace());
+
+ child = super.getChild(2);
+ assertValidity(ItemPSVI.VALIDITY_NOTKNOWN, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_NONE, child
+ .getValidationAttempted());
+ assertElementNull(child.getElementDeclaration());
+ assertAnyType(child.getTypeDefinition());
+ }
+
+ private void checkFalseResult() {
+ assertValidity(ItemPSVI.VALIDITY_VALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementNull(fRootNode.getElementDeclaration());
+ assertTypeName("Y", fRootNode.getTypeDefinition().getName());
+ assertTypeNamespaceNull(fRootNode.getTypeDefinition().getNamespace());
+
+ PSVIElementNSImpl child = super.getChild(1);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("A", child.getElementDeclaration().getName());
+ assertTypeName("Y", child.getTypeDefinition().getName());
+ assertTypeNamespaceNull(child.getTypeDefinition().getNamespace());
+
+ child = super.getChild(2);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementNull(child.getElementDeclaration());
+ assertTypeName("Y", child.getTypeDefinition().getName());
+ assertTypeNamespaceNull(child.getTypeDefinition().getNamespace());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/IgnoreXSITypeTest_C_C.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.sun.org.apache.xerces.internal.dom.PSVIElementNSImpl;
+import com.sun.org.apache.xerces.internal.xs.ItemPSVI;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class IgnoreXSITypeTest_C_C extends BaseTest {
+
+ protected String getXMLDocument() {
+ return "xsitype_C_C.xml";
+ }
+
+ protected String getSchemaFile() {
+ return "base.xsd";
+ }
+
+ public IgnoreXSITypeTest_C_C(String name) {
+ super(name);
+ }
+
+
+ @BeforeClass
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @AfterClass
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testDefaultDocument() {
+ try {
+ reset();
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ // default value of the feature is false
+ checkFalseResult();
+ }
+
+ @Test
+ public void testDefaultFragment() {
+ try {
+ reset();
+ validateFragment();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ // default value of the feature is false
+ checkFalseResult();
+ }
+
+ @Test
+ public void testSetFalseDocument() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, false);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkFalseResult();
+ }
+
+ @Test
+ public void testSetFalseFragment() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, false);
+ validateFragment();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkFalseResult();
+ }
+
+ @Test
+ public void testSetTrueDocument() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, true);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkTrueResult();
+ }
+
+ @Test
+ public void testSetTrueFragment() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, true);
+ validateFragment();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkTrueResult();
+ }
+
+ private void checkTrueResult() {
+ assertValidity(ItemPSVI.VALIDITY_NOTKNOWN, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_NONE, fRootNode
+ .getValidationAttempted());
+ assertElementNull(fRootNode.getElementDeclaration());
+ assertAnyType(fRootNode.getTypeDefinition());
+
+ PSVIElementNSImpl child = super.getChild(1);
+ assertValidity(ItemPSVI.VALIDITY_NOTKNOWN, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_NONE, child
+ .getValidationAttempted());
+ assertElementNull(child.getElementDeclaration());
+ assertAnyType(child.getTypeDefinition());
+ }
+
+ private void checkFalseResult() {
+ assertValidity(ItemPSVI.VALIDITY_VALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementNull(fRootNode.getElementDeclaration());
+ assertTypeName("Y", fRootNode.getTypeDefinition().getName());
+ assertTypeNamespaceNull(fRootNode.getTypeDefinition().getNamespace());
+
+ PSVIElementNSImpl child = super.getChild(1);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementNull(child.getElementDeclaration());
+ assertTypeName("Y", child.getTypeDefinition().getName());
+ assertTypeNamespaceNull(child.getTypeDefinition().getNamespace());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/IgnoreXSITypeTest_C_CA.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.sun.org.apache.xerces.internal.dom.PSVIElementNSImpl;
+import com.sun.org.apache.xerces.internal.xs.ItemPSVI;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class IgnoreXSITypeTest_C_CA extends BaseTest {
+
+ protected String getXMLDocument() {
+ return "xsitype_C_CA.xml";
+ }
+
+ protected String getSchemaFile() {
+ return "base.xsd";
+ }
+
+ public IgnoreXSITypeTest_C_CA(String name) {
+ super(name);
+ }
+
+ @BeforeClass
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @AfterClass
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testDefaultDocument() {
+ try {
+ reset();
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ // default value of the feature is false
+ checkFalseResult();
+ }
+
+ @Test
+ public void testDefaultFragment() {
+ try {
+ reset();
+ validateFragment();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ // default value of the feature is false
+ checkFalseResult();
+ }
+
+ @Test
+ public void testSetFalseDocument() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, false);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkFalseResult();
+ }
+
+ @Test
+ public void testSetFalseFragment() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, false);
+ validateFragment();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkFalseResult();
+ }
+
+ @Test
+ public void testSetTrueDocument() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, true);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkTrueResult();
+ }
+
+ @Test
+ public void testSetTrueFragment() {
+ try {
+ reset();
+ fValidator.setFeature(IGNORE_XSI_TYPE, true);
+ validateFragment();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkTrueResult();
+ }
+
+ private void checkTrueResult() {
+ assertValidity(ItemPSVI.VALIDITY_NOTKNOWN, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_PARTIAL, fRootNode
+ .getValidationAttempted());
+ assertElementNull(fRootNode.getElementDeclaration());
+ assertAnyType(fRootNode.getTypeDefinition());
+
+ PSVIElementNSImpl child = super.getChild(1);
+ assertValidity(ItemPSVI.VALIDITY_NOTKNOWN, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_NONE, child
+ .getValidationAttempted());
+ assertElementNull(child.getElementDeclaration());
+ assertAnyType(child.getTypeDefinition());
+
+ child = super.getChild(2);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("A", child.getElementDeclaration().getName());
+ assertTypeName("Y", child.getTypeDefinition().getName());
+ assertTypeNamespaceNull(child.getTypeDefinition().getNamespace());
+ }
+
+ private void checkFalseResult() {
+ assertValidity(ItemPSVI.VALIDITY_VALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementNull(fRootNode.getElementDeclaration());
+ assertTypeName("Y", fRootNode.getTypeDefinition().getName());
+ assertTypeNamespaceNull(fRootNode.getTypeDefinition().getNamespace());
+
+ PSVIElementNSImpl child = super.getChild(1);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementNull(child.getElementDeclaration());
+ assertTypeName("Y", child.getTypeDefinition().getName());
+ assertTypeNamespaceNull(child.getTypeDefinition().getNamespace());
+
+ child = super.getChild(2);
+ assertValidity(ItemPSVI.VALIDITY_VALID, child.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, child
+ .getValidationAttempted());
+ assertElementName("A", child.getElementDeclaration().getName());
+ assertTypeName("Y", child.getTypeDefinition().getName());
+ assertTypeNamespaceNull(child.getTypeDefinition().getNamespace());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/RootTypeDefinitionTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,235 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import javax.xml.namespace.QName;
+import com.sun.org.apache.xerces.internal.dom.PSVIElementNSImpl;
+import com.sun.org.apache.xerces.internal.impl.xs.SchemaSymbols;
+import com.sun.org.apache.xerces.internal.xs.ItemPSVI;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class RootTypeDefinitionTest extends BaseTest {
+ private QName unknownType;
+
+ private QName typeX;
+
+ private QName typeY;
+
+ private QName typeZ;
+
+ private QName typeOtherNamespace;
+
+ private final static String UNKNOWN_TYPE_ERROR = "cvc-type.1";
+
+ private final static String INVALID_DERIVATION_ERROR = "cvc-elt.4.3";
+
+ protected String getXMLDocument() {
+ return "base.xml";
+ }
+
+ protected String getSchemaFile() {
+ return "base.xsd";
+ }
+
+ protected String[] getRelevantErrorIDs() {
+ return new String[] { UNKNOWN_TYPE_ERROR, INVALID_DERIVATION_ERROR };
+ }
+
+ public RootTypeDefinitionTest(String name) {
+ super(name);
+ unknownType = new QName("W");
+ typeX = new QName("X");
+ typeY = new QName("Y");
+ typeZ = new QName("Z");
+ typeOtherNamespace = new QName("xslt.unittests", "W", "unit");
+ }
+
+
+ @BeforeClass
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @AfterClass
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testDefault() {
+ try {
+ reset();
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkDefault();
+ }
+
+ @Test
+ public void testSettingNull() {
+ try {
+ reset();
+ fValidator.setProperty(ROOT_TYPE, null);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkDefault();
+ }
+
+ @Test
+ public void testSettingToUnknownType() {
+ try {
+ reset();
+ fValidator.setProperty(ROOT_TYPE, unknownType);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ assertError(UNKNOWN_TYPE_ERROR);
+ checkDefault();
+ }
+
+ @Test
+ public void testSettingToEqualType() {
+ try {
+ reset();
+ fValidator.setProperty(ROOT_TYPE, typeX);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ assertValidity(ItemPSVI.VALIDITY_VALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementNull(fRootNode.getElementDeclaration());
+ assertTypeName("X", fRootNode.getTypeDefinition().getName());
+ }
+
+ @Test
+ public void testSettingToDerivedType() {
+ try {
+ reset();
+ // this is required to make it a valid type Y node
+ ((PSVIElementNSImpl) fRootNode).setAttributeNS(null, "attr", "typeY");
+ fValidator.setProperty(ROOT_TYPE, typeY);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ assertValidity(ItemPSVI.VALIDITY_VALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementNull(fRootNode.getElementDeclaration());
+ assertTypeName("Y", fRootNode.getTypeDefinition().getName());
+ }
+
+ @Test
+ public void testSettingToNonDerivedType() {
+ try {
+ reset();
+ fValidator.setProperty(ROOT_TYPE, typeZ);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ assertValidity(ItemPSVI.VALIDITY_VALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementNull(fRootNode.getElementDeclaration());
+ assertTypeName("Z", fRootNode.getTypeDefinition().getName());
+ }
+
+ @Test
+ public void testSettingToOtherSchemaType() {
+ try {
+ reset();
+ ((PSVIElementNSImpl) fRootNode).setAttributeNS(SchemaSymbols.URI_XSI,
+ SchemaSymbols.XSI_SCHEMALOCATION,
+ "xslt.unittests otherNamespace.xsd");
+ fValidator.setProperty(ROOT_TYPE, typeOtherNamespace);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ assertValidity(ItemPSVI.VALIDITY_VALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementNull(fRootNode.getElementDeclaration());
+ assertTypeName("W", fRootNode.getTypeDefinition().getName());
+ assertTypeNamespace("xslt.unittests", fRootNode.getTypeDefinition()
+ .getNamespace());
+ }
+
+ @Test
+ public void testSettingTypeAndXSIType() {
+ try {
+ reset();
+ // this is required to make it a valid type Y node
+ ((PSVIElementNSImpl) fRootNode).setAttributeNS(null, "attr", "typeY");
+ ((PSVIElementNSImpl) fRootNode).setAttributeNS(SchemaSymbols.URI_XSI,
+ SchemaSymbols.XSI_TYPE, "Y");
+ fValidator.setProperty(ROOT_TYPE, typeX);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ assertValidity(ItemPSVI.VALIDITY_VALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementNull(fRootNode.getElementDeclaration());
+ assertTypeName("Y", fRootNode.getTypeDefinition().getName());
+ }
+
+ @Test
+ public void testSettingTypeAndInvalidXSIType() {
+ try {
+ reset();
+ ((PSVIElementNSImpl) fRootNode).setAttributeNS(SchemaSymbols.URI_XSI,
+ SchemaSymbols.XSI_TYPE, "Z");
+ fValidator.setProperty(ROOT_TYPE, typeX);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ assertError(INVALID_DERIVATION_ERROR);
+ assertValidity(ItemPSVI.VALIDITY_INVALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementNull(fRootNode.getElementDeclaration());
+ assertTypeName("Z", fRootNode.getTypeDefinition().getName());
+ }
+
+ private void checkDefault() {
+ assertValidity(ItemPSVI.VALIDITY_VALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementName("A", fRootNode.getElementDeclaration().getName());
+ assertTypeName("X", fRootNode.getTypeDefinition().getName());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/SpecialCaseErrorHandler.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.HashMap;
+
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+public class SpecialCaseErrorHandler implements ErrorHandler {
+ public static final boolean DEBUG = false;
+
+ private HashMap<String, Boolean> errors;
+
+ public SpecialCaseErrorHandler(String[] specialCases) {
+ errors = new HashMap<>();
+ for (int i = 0; i < specialCases.length; ++i) {
+ errors.put(specialCases[i], Boolean.FALSE);
+ }
+ }
+
+ public void reset() {
+ errors.keySet().stream().forEach((error) -> {
+ errors.put(error, Boolean.FALSE);
+ });
+ }
+
+ @Override
+ public void warning(SAXParseException arg0) throws SAXException {
+ if (DEBUG) {
+ System.err.println(arg0.getMessage());
+ }
+ }
+
+ @Override
+ public void error(SAXParseException arg0) throws SAXException {
+ if (DEBUG) {
+ System.err.println(arg0.getMessage());
+ }
+ errors.keySet().stream().filter((error) -> (arg0.getMessage().startsWith(error))).forEach((error) -> {
+ errors.put(error, Boolean.TRUE);
+ });
+ }
+
+ public void fatalError(SAXParseException arg0) throws SAXException {
+ throw arg0;
+ }
+
+ public boolean specialCaseFound(String key) {
+ return ((Boolean) errors.get(key)).booleanValue();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/TEST.properties Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,3 @@
+# This file identifies root(s) of the test-ng hierarchy.
+
+TestNG.dirs = .
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/UnparsedEntityCheckingTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.sun.org.apache.xerces.internal.dom.PSVIElementNSImpl;
+import com.sun.org.apache.xerces.internal.xs.ItemPSVI;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class UnparsedEntityCheckingTest extends BaseTest {
+ public static final String UNDECLARED_ENTITY = "UndeclaredEntity";
+
+ protected String getXMLDocument() {
+ return "unparsedEntity.xml";
+ }
+
+ protected String getSchemaFile() {
+ return "base.xsd";
+ }
+
+ protected String[] getRelevantErrorIDs() {
+ return new String[] { UNDECLARED_ENTITY };
+ }
+
+ public UnparsedEntityCheckingTest(String name) {
+ super(name);
+ }
+
+ @BeforeClass
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @AfterClass
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testDefaultValid() {
+ try {
+ reset();
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkDefault();
+ }
+
+ @Test
+ public void testSetFalseValid() {
+ try {
+ reset();
+ fValidator.setFeature(UNPARSED_ENTITY_CHECKING, false);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkDefault();
+ }
+
+ @Test
+ public void testSetTrueValid() {
+ try {
+ reset();
+ fValidator.setFeature(UNPARSED_ENTITY_CHECKING, true);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkDefault();
+ }
+
+ @Test
+ public void testDefaultInvalid() {
+ try {
+ reset();
+ ((PSVIElementNSImpl) fRootNode).setAttributeNS(null,
+ "unparsedEntityAttr", "invalid");
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkInvalid();
+ }
+
+ @Test
+ public void testSetFalseInvalid() {
+ try {
+ reset();
+ ((PSVIElementNSImpl) fRootNode).setAttributeNS(null,
+ "unparsedEntityAttr", "invalid");
+ fValidator.setFeature(UNPARSED_ENTITY_CHECKING, false);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkDefault();
+ }
+
+ @Test
+ public void testSetTrueInvalid() {
+ try {
+ reset();
+ ((PSVIElementNSImpl) fRootNode).setAttributeNS(null,
+ "unparsedEntityAttr", "invalid");
+ fValidator.setFeature(UNPARSED_ENTITY_CHECKING, true);
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ checkInvalid();
+ }
+
+ private void checkDefault() {
+ assertNoError(UNDECLARED_ENTITY);
+ assertValidity(ItemPSVI.VALIDITY_VALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementName("A", fRootNode.getElementDeclaration().getName());
+ assertTypeName("X", fRootNode.getTypeDefinition().getName());
+ }
+
+ private void checkInvalid() {
+ assertError(UNDECLARED_ENTITY);
+ assertValidity(ItemPSVI.VALIDITY_INVALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementName("A", fRootNode.getElementDeclaration().getName());
+ assertTypeName("X", fRootNode.getTypeDefinition().getName());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/UseGrammarPoolOnlyTest_False.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.sun.org.apache.xerces.internal.xs.ItemPSVI;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class UseGrammarPoolOnlyTest_False extends BaseTest {
+ private final static String UNKNOWN_TYPE_ERROR = "cvc-type.1";
+
+ private final static String INVALID_DERIVATION_ERROR = "cvc-elt.4.3";
+
+ protected String getXMLDocument() {
+ return "otherNamespace.xml";
+ }
+
+ protected String getSchemaFile() {
+ return "base.xsd";
+ }
+
+ protected String[] getRelevantErrorIDs() {
+ return new String[] { UNKNOWN_TYPE_ERROR, INVALID_DERIVATION_ERROR };
+ }
+
+ protected boolean getUseGrammarPoolOnly() {
+ return false;
+ }
+
+ public UseGrammarPoolOnlyTest_False(String name) {
+ super(name);
+ }
+
+ @BeforeClass
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @AfterClass
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * The purpose of this test is to check if setting the USE_GRAMMAR_POOL_ONLY
+ * feature to true causes external schemas to not be read. This
+ * functionality already existed prior to adding the XSLT 2.0 validation
+ * features; however, because the class that controlled it changed, this
+ * test simply ensures that the existing functionality did not disappear.
+ * -PM
+ */
+ @Test
+ public void testUsingOnlyGrammarPool() {
+ try {
+ reset();
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ assertValidity(ItemPSVI.VALIDITY_VALID, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_FULL, fRootNode
+ .getValidationAttempted());
+ assertElementName("A", fRootNode.getElementDeclaration().getName());
+ assertElementNamespace("xslt.unittests", fRootNode
+ .getElementDeclaration().getNamespace());
+ assertTypeName("W", fRootNode.getTypeDefinition().getName());
+ assertTypeNamespace("xslt.unittests", fRootNode.getTypeDefinition()
+ .getNamespace());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/UseGrammarPoolOnlyTest_True.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.sun.org.apache.xerces.internal.xs.ItemPSVI;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class UseGrammarPoolOnlyTest_True extends BaseTest {
+
+ protected String getXMLDocument() {
+ return "otherNamespace.xml";
+ }
+
+ protected String getSchemaFile() {
+ return "base.xsd";
+ }
+
+ protected boolean getUseGrammarPoolOnly() {
+ return true;
+ }
+
+ public UseGrammarPoolOnlyTest_True(String name) {
+ super(name);
+ }
+
+ @BeforeClass
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @AfterClass
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * The purpose of this test is to check if setting the USE_GRAMMAR_POOL_ONLY
+ * feature to true causes external schemas to not be read. This
+ * functionality already existed prior to adding the XSLT 2.0 validation
+ * features; however, because the class that controlled it changed, this
+ * test simply ensures that the existing functionality did not disappear.
+ * -PM
+ */
+ @Test
+ public void testUsingOnlyGrammarPool() {
+ try {
+ reset();
+ validateDocument();
+ } catch (Exception e) {
+ fail("Validation failed: " + e.getMessage());
+ }
+
+ assertValidity(ItemPSVI.VALIDITY_NOTKNOWN, fRootNode.getValidity());
+ assertValidationAttempted(ItemPSVI.VALIDATION_NONE, fRootNode
+ .getValidationAttempted());
+ assertElementNull(fRootNode.getElementDeclaration());
+ assertAnyType(fRootNode.getTypeDefinition());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/base.xml Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,3 @@
+<?xml version="1.0"?>
+<A attr="typeX">
+</A>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/base.xsd Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,74 @@
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+ <xsd:element name="A" type="X"/>
+
+ <!-- The purpose of this element is:
+ a) To have a fixed attribute use
+ b) To have an attribute with a fixed attribute declaration
+ c) To have a complex type with simple content and a fixed value
+ d) To have an element declaration with a fixed value
+ -->
+ <xsd:element name="B" fixed="howdy">
+ <xsd:complexType>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute ref="fixedAttr" use="required" fixed="hello"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="D" type="xsd:string" fixed="hey"/>
+
+ <xsd:attribute name="attr" type="xsd:string"/>
+
+ <xsd:attribute name="unparsedEntityAttr" type="xsd:ENTITIES"/>
+
+ <xsd:attribute name="fixedAttr" type="xsd:string" fixed="hello"/>
+
+ <xsd:complexType name="X">
+ <xsd:sequence>
+ <xsd:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute ref="attr"/>
+ <xsd:attribute ref="unparsedEntityAttr"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="Y">
+ <xsd:complexContent>
+ <xsd:restriction base="X">
+ <xsd:sequence>
+ <xsd:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute ref="attr" fixed="typeY"/>
+ <xsd:attribute ref="unparsedEntityAttr" use="prohibited"/>
+ </xsd:restriction>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <!-- Z is the same as X, but is not derived from X. -->
+ <xsd:complexType name="Z">
+ <xsd:sequence>
+ <xsd:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute ref="attr"/>
+ <xsd:attribute ref="unparsedEntityAttr"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="idType">
+ <xsd:complexContent>
+ <xsd:extension base="X">
+ <xsd:attribute name="idAttr" type="xsd:ID"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="idrefType">
+ <xsd:complexContent>
+ <xsd:extension base="X">
+ <xsd:attribute name="idrefAttr" type="xsd:IDREF"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+
+</xsd:schema>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/fixedAttr.xml Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<A>
+ <B fixedAttr="hello">howdy</B>
+ <D>hey</D>
+</A>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/idIdref.xml Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <A xsi:type="idType" idAttr="ONE"/>
+ <A xsi:type="idType" idAttr="ONE"/>
+ <A xsi:type="idrefType" idrefAttr="TWO"/>
+</A>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/idc.xml Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<itemList>
+ <item uniqueAttr="ONE">1</item>
+ <item uniqueAttr="ONE">2</item>
+ <item uniqueAttr="TWO">2</item>
+ <itemRef>3</itemRef>
+</itemList>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/idc.xsd Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,41 @@
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+ <xsd:element name="itemList" type="itemListType">
+ <xsd:unique name="itemAttr">
+ <xsd:selector xpath="item"/>
+ <xsd:field xpath="@uniqueAttr"/>
+ </xsd:unique>
+
+ <xsd:key name="itemValueKey">
+ <xsd:selector xpath="item"/>
+ <xsd:field xpath="."/>
+ </xsd:key>
+
+ <xsd:keyref name="itemKeyRef" refer="itemValueKey">
+ <xsd:selector xpath="itemRef"/>
+ <xsd:field xpath="."/>
+ </xsd:keyref>
+ </xsd:element>
+
+ <xsd:element name="item" type="itemType"/>
+
+ <xsd:attribute name="uniqueAttr" type="xsd:string"/>
+
+ <xsd:attribute name="unparsedEntityAttr" type="xsd:ENTITIES"/>
+
+ <xsd:complexType name="itemListType">
+ <xsd:sequence>
+ <xsd:element ref="item" maxOccurs="unbounded"/>
+ <xsd:element name="itemRef" type="xsd:string" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="itemType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute ref="uniqueAttr" use="required"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+</xsd:schema>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/otherNamespace.xml Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<unit:A xmlns:unit="xslt.unittests"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="xslt.unittests otherNamespace.xsd"
+ attr="typeX">
+</unit:A>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/otherNamespace.xsd Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,18 @@
+<xsd:schema
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:unit="xslt.unittests"
+ targetNamespace="xslt.unittests">
+
+ <xsd:import schemaLocation="base.xsd"/>
+
+ <xsd:element name="A" type="unit:W"/>
+
+ <xsd:complexType name="W">
+ <xsd:sequence>
+ <xsd:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute ref="attr"/>
+ <xsd:attribute ref="unparsedEntityAttr"/>
+ </xsd:complexType>
+
+</xsd:schema>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/unparsedEntity.dtd Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,3 @@
+<!NOTATION myNotation SYSTEM "somethingElse" >
+<!ENTITY myUnparsedEntity SYSTEM "something" NDATA myNotation >
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/unparsedEntity.xml Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<!DOCTYPE personnel SYSTEM "unparsedEntity.dtd">
+<A attr="blah" unparsedEntityAttr="myUnparsedEntity">
+</A>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/xsitype_A_A.xml Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<A attr="typeY"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:type="Y">
+ <A attr="typeY" xsi:type="Y"/>
+</A>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/xsitype_A_C.xml Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<A attr="typeY"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:type="Y">
+ <C attr="typeY" xsi:type="Y"/>
+</A>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/xsitype_C_A.xml Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<C attr="typeY"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:type="Y">
+ <A attr="typeY" xsi:type="Y"/>
+</C>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/xsitype_C_AC.xml Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<C attr="typeY"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:type="Y">
+ <A attr="typeY" xsi:type="Y"/>
+ <C attr="typeY" xsi:type="Y"/>
+</C>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/xsitype_C_C.xml Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<C attr="typeY"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:type="Y">
+ <C attr="typeY" xsi:type="Y"/>
+</C>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/xml/jaxp/testng/validation/8037819/xsitype_C_CA.xml Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<C attr="typeY"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:type="Y">
+ <C attr="typeY" xsi:type="Y"/>
+ <A attr="typeY" xsi:type="Y"/>
+</C>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/lib/testlibrary/JavaToolUtils.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.file.Files;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+/**
+ * Utils class for compiling , creating jar file and executing a java command
+ *
+ * @author Raghu Nair
+ */
+
+public class JavaToolUtils {
+
+ public static final long DEFAULT_WAIT_TIME = 10000;
+
+ private JavaToolUtils() {
+ }
+
+ /**
+ * Takes a list of files and compile these files into the working directory.
+ *
+ * @param files
+ * @throws IOException
+ */
+ public static void compileFiles(List<File> files) throws IOException {
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+ try (StandardJavaFileManager fileManager = compiler.
+ getStandardFileManager(null, null, null)) {
+ Iterable<? extends JavaFileObject> compilationUnit
+ = fileManager.getJavaFileObjectsFromFiles(files);
+ compiler.getTask(null, fileManager, null, null, null,
+ compilationUnit).call();
+ }
+ }
+
+ /**
+ * Create a jar file using the list of files provided.
+ *
+ * @param jar
+ * @param files
+ * @throws IOException
+ */
+ public static void createJar(File jar, List<File> files)
+ throws IOException {
+ Manifest manifest = new Manifest();
+ manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION,
+ "1.0");
+ try (JarOutputStream target = new JarOutputStream(
+ new FileOutputStream(jar), manifest)) {
+ for (File file : files) {
+ add(file, target);
+ }
+ }
+ }
+
+ private static void add(File source, JarOutputStream target)
+ throws IOException {
+ Objects.requireNonNull(source, "source cannot be null");
+ Objects.requireNonNull(target, "target cannot be null");
+ // not tested against directories and from different path.
+ String name = source.getName();
+ if (source.isDirectory()) {
+ if (!name.isEmpty()) {
+ if (!name.endsWith("/")) {
+ name += "/";
+ }
+ JarEntry entry = new JarEntry(name);
+ entry.setTime(source.lastModified());
+ target.putNextEntry(entry);
+ target.closeEntry();
+ }
+ for (File nestedFile : source.listFiles()) {
+ add(nestedFile, target);
+ }
+ return;
+ }
+ System.out.println("Adding entry " + name);
+ JarEntry entry = new JarEntry(name);
+ entry.setTime(source.lastModified());
+ target.putNextEntry(entry);
+ Files.copy(source.toPath(), target);
+ target.closeEntry();
+ }
+
+ /**
+ * Runs java command with provided arguments. Caller should not pass java
+ * command in the argument list.
+ *
+ * @param commands
+ * @param waitTime time to wait for the command to exit in milli seconds
+ * @return
+ * @throws Exception
+ */
+ public static int runJava(List<String> commands,long waitTime)
+ throws Exception {
+ String java = System.getProperty("java.home") + "/bin/java";
+ commands.add(0, java);
+ String command = commands.toString().replace(",", " ");
+ System.out.println("Executing the following command \n" + command);
+ ProcessBuilder processBuilder = new ProcessBuilder(commands);
+ final Process process = processBuilder.start();
+ BufferedReader errorStream = new BufferedReader(
+ new InputStreamReader(process.getErrorStream()));
+ BufferedReader outStream = new BufferedReader(
+ new InputStreamReader(process.getInputStream()));
+ String errorLine;
+ StringBuilder errors = new StringBuilder();
+ String outLines;
+ while ((errorLine = errorStream.readLine()) != null) {
+ errors.append(errorLine).append("\n");
+ }
+ while ((outLines = outStream.readLine()) != null) {
+ System.out.println(outLines);
+ }
+ errorLine = errors.toString();
+ System.err.println(errorLine);
+ process.waitFor(waitTime, TimeUnit.MILLISECONDS);
+ int exitStatus = process.exitValue();
+ if (exitStatus != 0 && errorLine != null && errorLine.isEmpty()) {
+ throw new RuntimeException(errorLine);
+ }
+ return exitStatus;
+ }
+
+ /**
+ * Runs java command with provided arguments. Caller should not pass java
+ * command in the argument list.
+ *
+ * @param commands
+ * @return
+ * @throws Exception
+ */
+ public static int runJava(List<String> commands) throws Exception {
+ return runJava(commands, DEFAULT_WAIT_TIME);
+ }
+
+ /**
+ * Run any command
+ * @param commands
+ * @return
+ * @throws Exception
+ */
+ public static int runCommand(List<String> commands) throws Exception {
+ String command = commands.toString().replace(",", " ");
+ System.out.println("Executing the following command \n" + command);
+ ProcessBuilder processBuilder = new ProcessBuilder(commands);
+ final Process process = processBuilder.start();
+ BufferedReader errorStream = new BufferedReader(
+ new InputStreamReader(process.getErrorStream()));
+ BufferedReader outStream = new BufferedReader(
+ new InputStreamReader(process.getInputStream()));
+ String errorLine;
+ StringBuilder errors = new StringBuilder();
+ String outLines;
+ while ((errorLine = errorStream.readLine()) != null) {
+ errors.append(errorLine).append("\n");
+ }
+ while ((outLines = outStream.readLine()) != null) {
+ System.out.println(outLines);
+ }
+ errorLine = errors.toString();
+ System.err.println(errorLine);
+ int exitStatus = process.exitValue();
+ if (exitStatus != 0 && errorLine != null && errorLine.isEmpty()) {
+ throw new RuntimeException(errorLine);
+ }
+ return exitStatus;
+ }
+
+
+}
--- a/jdk/test/sun/management/jmxremote/startstop/JMXStartStopTest.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/test/sun/management/jmxremote/startstop/JMXStartStopTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -26,7 +26,7 @@
import java.lang.reflect.Method;
import java.net.ConnectException;
import java.net.ServerSocket;
-import java.rmi.NoSuchObjectException;
+import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;
@@ -174,9 +174,9 @@
} catch (Exception e) {
Throwable t = e;
while (t != null) {
- if (t instanceof NoSuchObjectException ||
- t instanceof ConnectException ||
- t instanceof SSLHandshakeException) {
+ if (t instanceof RemoteException ||
+ t instanceof SSLHandshakeException ||
+ t instanceof ConnectException) {
break;
}
t = t.getCause();
@@ -617,7 +617,10 @@
busyPort = ss.getLocalPort();
jcmd(
line -> {
- if (line.contains("Port already in use: " + busyPort)) {
+ boolean match = line.contains("Port already in use: " +
+ busyPort);
+ System.out.println("[match] " + line + " => " + match);
+ if (match) {
checks.getAndUpdate((op) -> op | 4);
}
},
--- a/jdk/test/sun/text/resources/LocaleData Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/test/sun/text/resources/LocaleData Wed Jul 05 19:59:54 2017 +0200
@@ -7696,3 +7696,6 @@
# bug 8037343
FormatData/es_DO/DatePatterns/2=dd/MM/yyyy
FormatData/es_DO/DatePatterns/3=dd/MM/yy
+
+# bug 8055222
+CurrencyNames/lt_LT/EUR=\u20AC
--- a/jdk/test/sun/text/resources/LocaleDataTest.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/test/sun/text/resources/LocaleDataTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -36,7 +36,7 @@
* 6919624 6998391 7019267 7020960 7025837 7020583 7036905 7066203 7101495
* 7003124 7085757 7028073 7171028 7189611 8000983 7195759 8004489 8006509
* 7114053 7074882 7040556 8013836 8021121 6192407 6931564 8027695 8017142
- * 8037343
+ * 8037343 8055222
* @summary Verify locale data
*
*/
--- a/jdk/test/sun/tools/jstatd/JstatdTest.java Thu Sep 04 13:26:26 2014 -0700
+++ b/jdk/test/sun/tools/jstatd/JstatdTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -148,11 +148,12 @@
private OutputAnalyzer waitForJstatdRMI(ProcessBuilder pb) throws IOException, InterruptedException {
OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ String remoteHost = (serverName != null) ? serverName : "JStatRemoteHost";
while (output.getExitValue() != 0) {
String out = output.getOutput();
if (out.contains("RMI Registry not available") ||
- out.contains("RMI Server JStatRemoteHost not available")) {
+ out.contains("RMI Server " + remoteHost + " not available")) {
Thread.sleep(100);
output = new OutputAnalyzer(pb.start());
} else {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/util/locale/provider/Bug8038436.java Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2014, 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 8038436
+ * @summary Test for changes in 8038436
+ * @compile -XDignore.symbol.file Bug8038436.java
+ * @run main/othervm Bug8038436 -Djava.ext.dirs=foo security
+ * @run main/othervm Bug8038436 -Djava.locale.providers=JRE availlocs
+ */
+
+import java.security.*;
+import java.text.*;
+import java.util.*;
+import java.util.stream.*;
+import sun.util.locale.provider.*;
+
+public class Bug8038436 {
+ public static void main(String[] args) {
+ switch (args[1]) {
+ case "security":
+ securityTests();
+ break;
+ case "availlocs":
+ availableLocalesTests();
+ break;
+ default:
+ throw new RuntimeException("no test was specified.");
+ }
+ }
+
+ private static void securityTests() {
+ Policy.setPolicy(new MyPolicy());
+ System.setSecurityManager(new SecurityManager());
+
+ /*
+ * Test for AccessClassInPackage security exception. Confirms that
+ * exeption won't be thrown if an application sets a Permission that
+ * does not allow any RuntimePermission, on loading LocaleDataMetaInfo
+ * from jdk.localedata module.
+ */
+ System.out.println(new Formatter(Locale.JAPAN).format("%1$tB %1$te, %1$tY",
+ new GregorianCalendar()));
+
+ /*
+ * Check only English/ROOT locales are returned if the jdk.localedata
+ * module is not installed (implied by "java.ext.dirs" set to "foo").
+ */
+ if (Arrays.asList(Locale.getAvailableLocales())
+ .stream()
+ .anyMatch(l -> l != Locale.ROOT && l.getLanguage() != "en")) {
+ throw new RuntimeException("non English locale(s) included in available locales");
+ }
+ }
+
+
+ static class MyPolicy extends Policy {
+ final PermissionCollection perms = new Permissions();
+
+ MyPolicy() {
+ // allows no RuntimePermission
+ }
+
+ public PermissionCollection getPermissions(ProtectionDomain domain) {
+ return perms;
+ }
+
+ public PermissionCollection getPermissions(CodeSource codesource) {
+ return perms;
+ }
+
+ public boolean implies(ProtectionDomain domain, Permission perm) {
+ return perms.implies(perm);
+ }
+ }
+
+ static final String[] bipLocs = ("ar, ar-JO, ar-LB, ar-SY, be, be-BY, bg, " +
+ "bg-BG, ca, ca-ES, cs, cs-CZ, da, da-DK, de, de-AT, de-CH, de-DE, " +
+ "de-LU, el, el-CY, el-GR, en, en-AU, en-CA, en-GB, en-IE, en-IN, " +
+ "en-MT, en-NZ, en-PH, en-SG, en-US, en-ZA, es, es-AR, es-BO, es-CL, " +
+ "es-CO, es-CR, es-DO, es-EC, es-ES, es-GT, es-HN, es-MX, es-NI, " +
+ "es-PA, es-PE, es-PR, es-PY, es-SV, es-US, es-UY, es-VE, et, et-EE, " +
+ "fi, fi-FI, fr, fr-BE, fr-CA, fr-CH, fr-FR, ga, ga-IE, he, he-IL, " +
+ "hi-IN, hr, hr-HR, hu, hu-HU, id, id-ID, is, is-IS, it, it-CH, it-IT, " +
+ "ja, ja-JP, ko, ko-KR, lt, lt-LT, lv, lv-LV, mk, mk-MK, ms, ms-MY, mt, " +
+ "mt-MT, nl, nl-BE, nl-NL, no, no-NO, no-NO, pl, pl-PL, pt, pt-BR, " +
+ "pt-PT, ro, ro-RO, ru, ru-RU, sk, sk-SK, sl, sl-SI, sq, sq-AL, sr, " +
+ "sr-BA, sr-CS, sr-Latn, sr-Latn-ME, sr-ME, sr-RS, sv, sv-SE, th, th-TH, " +
+ "tr, tr-TR, uk, uk-UA, und, vi, vi-VN, zh, zh-CN, zh-HK, zh-Hans-CN, " +
+ "zh-Hans-SG, zh-Hant-HK, zh-Hant-TW, zh-SG, zh-TW, ").split(",\\s*");
+ static final String[] dfpLocs = bipLocs;
+ static final String[] datefspLocs = bipLocs;
+ static final String[] decimalfspLocs = bipLocs;
+ static final String[] calnpLocs = bipLocs;
+ static final String[] cpLocs = ("ar, be, bg, ca, cs, da, el, es, et, fi, " +
+ "fr, he, hi, hr, hu, is, ja, ko, lt, lv, mk, no, pl, ro, ru, sk, sl, " +
+ "sq, sr, sr-Latn, sv, th, tr, uk, und, vi, zh, zh-HK, zh-Hant-HK, " +
+ "zh-Hant-TW, zh-TW, ").split(",\\s*");
+ static final String[] nfpLocs = ("ar, ar-AE, ar-BH, ar-DZ, ar-EG, ar-IQ, " +
+ "ar-JO, ar-KW, ar-LB, ar-LY, ar-MA, ar-OM, ar-QA, ar-SA, ar-SD, ar-SY, " +
+ "ar-TN, ar-YE, be, be-BY, bg, bg-BG, ca, ca-ES, cs, cs-CZ, da, da-DK, " +
+ "de, de-AT, de-CH, de-DE, de-GR, de-LU, el, el-CY, el-GR, en, en-AU, " +
+ "en-CA, en-GB, en-IE, en-IN, en-MT, en-NZ, en-PH, en-SG, en-US, en-ZA, " +
+ "es, es-AR, es-BO, es-CL, es-CO, es-CR, es-CU, es-DO, es-EC, es-ES, " +
+ "es-GT, es-HN, es-MX, es-NI, es-PA, es-PE, es-PR, es-PY, es-SV, es-US, " +
+ "es-UY, es-VE, et, et-EE, fi, fi-FI, fr, fr-BE, fr-CA, fr-CH, fr-FR, " +
+ "fr-LU, ga, ga-IE, he, he-IL, hi, hi-IN, hr, hr-HR, hu, hu-HU, id, " +
+ "id-ID, is, is-IS, it, it-CH, it-IT, ja, ja-JP, " +
+ "ja-JP-u-ca-japanese-x-lvariant-JP, ko, ko-KR, lt, lt-LT, lv, lv-LV, " +
+ "mk, mk-MK, ms, ms-MY, mt, mt-MT, nb-NO, nl, nl-BE, nl-NL, nn-NO, " +
+ "nn-NO, no, no-NO, pl, pl-PL, pt, pt-BR, pt-PT, ro, ro-RO, ru, ru-RU, " +
+ "sk, sk-SK, sl, sl-SI, sq, sq-AL, sr, sr-BA, sr-CS, sr-Latn, " +
+ "sr-Latn-BA, sr-Latn-ME, sr-Latn-RS, sr-ME, sr-RS, sv, sv-SE, th, " +
+ "th-TH, th-TH-u-nu-thai-x-lvariant-TH, tr, tr-TR, uk, uk-UA, und, vi, " +
+ "vi-VN, zh, zh-CN, zh-HK, zh-Hans-CN, zh-Hans-SG, zh-Hant-HK, " +
+ "zh-Hant-TW, zh-SG, zh-TW, ").split(",\\s*");
+ static final String[] currencynpLocs = ("ar-AE, ar-BH, ar-DZ, ar-EG, ar-IQ, " +
+ "ar-JO, ar-KW, ar-LB, ar-LY, ar-MA, ar-OM, ar-QA, ar-SA, ar-SD, ar-SY, " +
+ "ar-TN, ar-YE, be-BY, bg-BG, ca-ES, cs-CZ, da-DK, de, de-AT, de-CH, " +
+ "de-DE, de-GR, de-LU, el-CY, el-GR, en-AU, en-CA, en-GB, en-IE, en-IN, " +
+ "en-MT, en-NZ, en-PH, en-SG, en-US, en-ZA, es, es-AR, es-BO, es-CL, " +
+ "es-CO, es-CR, es-CU, es-DO, es-EC, es-ES, es-GT, es-HN, es-MX, es-NI, " +
+ "es-PA, es-PE, es-PR, es-PY, es-SV, es-US, es-UY, es-VE, et-EE, fi-FI, " +
+ "fr, fr-BE, fr-CA, fr-CH, fr-FR, fr-LU, ga-IE, he-IL, hi-IN, hr-HR, " +
+ "hu-HU, id-ID, is-IS, it, it-CH, it-IT, ja, ja-JP, ko, ko-KR, lt-LT, " +
+ "lv-LV, mk-MK, ms-MY, mt-MT, nl-BE, nl-NL, no-NO, pl-PL, pt, pt-BR, " +
+ "pt-PT, ro-RO, ru-RU, sk-SK, sl-SI, sq-AL, sr-BA, sr-CS, sr-Latn-BA, " +
+ "sr-Latn-ME, sr-Latn-RS, sr-ME, sr-RS, sv, sv-SE, th-TH, tr-TR, uk-UA, " +
+ "und, vi-VN, zh-CN, zh-HK, zh-Hans-CN, zh-Hans-SG, zh-Hant-HK, " +
+ "zh-Hant-TW, zh-SG, zh-TW, ").split(",\\s*");
+ static final String[] lnpLocs = ("ar, be, bg, ca, cs, da, de, el, el-CY, " +
+ "en, en-MT, en-PH, en-SG, es, es-US, et, fi, fr, ga, he, hi, hr, hu, " +
+ "id, is, it, ja, ko, lt, lv, mk, ms, mt, nl, no, no-NO, pl, pt, pt-BR, " +
+ "pt-PT, ro, ru, sk, sl, sq, sr, sr-Latn, sv, th, tr, uk, und, vi, zh, " +
+ "zh-HK, zh-Hans-SG, zh-Hant-HK, zh-Hant-TW, zh-SG, zh-TW, ").split(",\\s*");
+ static final String[] tznpLocs = ("de, en, en-CA, en-GB, en-IE, es, fr, hi, " +
+ "it, ja, ko, pt-BR, sv, und, zh-CN, zh-HK, zh-Hans-CN, zh-Hant-HK, " +
+ "zh-Hant-TW, zh-TW, ").split(",\\s*");
+ static final String[] caldpLocs = ("ar, be, bg, ca, cs, da, de, el, el-CY, " +
+ "en, en-GB, en-IE, en-MT, es, es-ES, es-US, et, fi, fr, fr-CA, he, hi, " +
+ "hr, hu, id-ID, is, it, ja, ko, lt, lv, mk, ms-MY, mt, mt-MT, nl, no, " +
+ "pl, pt, pt-BR, pt-PT, ro, ru, sk, sl, sq, sr, sr-Latn-BA, sr-Latn-ME, " +
+ "sr-Latn-RS, sv, th, tr, uk, und, vi, zh, ").split(",\\s*");
+ static final String[] calpLocs = caldpLocs;
+
+ /*
+ * Validate whether JRE's *Providers return supported locales list based on
+ * their actual resource bundle exsistence. The above golden data
+ * are manually extracted, so they need to be updated if new locale
+ * data resource bundle were added.
+ */
+ private static void availableLocalesTests() {
+ LocaleProviderAdapter jre = LocaleProviderAdapter.forJRE();
+
+ checkAvailableLocales("BreakIteratorProvider",
+ jre.getBreakIteratorProvider().getAvailableLocales(), bipLocs);
+ checkAvailableLocales("CollatorProvider",
+ jre.getCollatorProvider().getAvailableLocales(), cpLocs);
+ checkAvailableLocales("DateFormatProvider",
+ jre.getDateFormatProvider().getAvailableLocales(), dfpLocs);
+ checkAvailableLocales("DateFormatSymbolsProvider",
+ jre.getDateFormatSymbolsProvider().getAvailableLocales(), datefspLocs);
+ checkAvailableLocales("DecimalFormatSymbolsProvider",
+ jre.getDecimalFormatSymbolsProvider().getAvailableLocales(), decimalfspLocs);
+ checkAvailableLocales("NumberFormatProvider",
+ jre.getNumberFormatProvider().getAvailableLocales(), nfpLocs);
+ checkAvailableLocales("CurrencyNameProvider",
+ jre.getCurrencyNameProvider().getAvailableLocales(), currencynpLocs);
+ checkAvailableLocales("LocaleNameProvider",
+ jre.getLocaleNameProvider().getAvailableLocales(), lnpLocs);
+ checkAvailableLocales("TimeZoneNameProvider",
+ jre.getTimeZoneNameProvider().getAvailableLocales(), tznpLocs);
+ checkAvailableLocales("CalendarDataProvider",
+ jre.getCalendarDataProvider().getAvailableLocales(), caldpLocs);
+ checkAvailableLocales("CalendarNameProvider",
+ jre.getCalendarNameProvider().getAvailableLocales(), calnpLocs);
+ checkAvailableLocales("CalendarProvider",
+ jre.getCalendarProvider().getAvailableLocales(), calpLocs);
+ }
+
+ private static void checkAvailableLocales(String testName, Locale[] got, String[] expected) {
+ System.out.println("Testing available locales for " + testName);
+ List<Locale> gotList = Arrays.asList(got).stream()
+ .map(Locale::toLanguageTag)
+ .sorted()
+ .map(Locale::forLanguageTag)
+ .collect(Collectors.toList());
+ List<Locale> expectedList = Arrays.asList(expected).stream()
+ .map(Locale::forLanguageTag)
+ .collect(Collectors.toList());
+
+ if (!gotList.equals(expectedList)) {
+ throw new RuntimeException("\n" + gotList.toString() + "\n is not equal to \n" +
+ expectedList.toString());
+ }
+ }
+}
--- a/make/CompileJavaModules.gmk Thu Sep 04 13:26:26 2014 -0700
+++ b/make/CompileJavaModules.gmk Wed Jul 05 19:59:54 2017 +0200
@@ -89,7 +89,7 @@
################################################################################
-java.desktop_COPY := .gif .png .wav .txt .xml .css flavormap.properties
+java.desktop_COPY := .gif .png .wav .txt .xml .css flavormap.properties .pf
java.desktop_CLEAN := iio-plugin.properties
java.desktop_EXCLUDES += \
--- a/make/Main.gmk Thu Sep 04 13:26:26 2014 -0700
+++ b/make/Main.gmk Wed Jul 05 19:59:54 2017 +0200
@@ -236,11 +236,11 @@
# Creates the jar files (rt.jar resources.jar etc)
main-jars:
- +($(CD) $(JDK_TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f CreateJars.gmk)
+ +($(CD) $(JDK_TOPDIR)/make && $(MAKE) $(MAKE_ARGS) PROFILE="" -f CreateJars.gmk)
# Creates the images (j2sdk-image j2re-image etc)
images:
- +($(CD) $(JDK_TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f Images.gmk)
+ +($(CD) $(JDK_TOPDIR)/make && $(MAKE) $(MAKE_ARGS) PROFILE="" -f Images.gmk)
ifeq ($(OPENJDK_TARGET_OS), macosx)
+($(CD) $(JDK_TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f Bundles.gmk)
endif
--- a/make/common/MakeBase.gmk Thu Sep 04 13:26:26 2014 -0700
+++ b/make/common/MakeBase.gmk Wed Jul 05 19:59:54 2017 +0200
@@ -349,7 +349,7 @@
# (and causing a crash on Cygwin).
# Default shell seems to always be /bin/sh. Must override with bash to get this to work on Solaris.
# Only use time if it's GNU time which supports format and output file.
- WRAPPER_SHELL:=/bin/bash $$(SRC_ROOT)/common/bin/shell-tracer.sh $$(if $$(findstring yes,$$(IS_GNU_TIME)),$$(TIME),-) $$(OUTPUT_ROOT)/build-trace-time.log /bin/bash
+ WRAPPER_SHELL:=$$(BASH) $$(SRC_ROOT)/common/bin/shell-tracer.sh $$(if $$(findstring yes,$$(IS_GNU_TIME)),$$(TIME),-) $$(OUTPUT_ROOT)/build-trace-time.log /bin/bash
SHELL=$$(warning $$(if $$@,Building $$@,Running shell command) $$(if $$<, (from $$<))$$(if $$?, ($$(wordlist 1, 20, $$?) $$(if $$(wordlist 21, 22, $$?), ... [in total $$(words $$?) files]) newer)))$$(WRAPPER_SHELL)
endif
# Never remove warning messages; this is just for completeness
--- a/nashorn/.hgtags Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/.hgtags Wed Jul 05 19:59:54 2017 +0200
@@ -262,3 +262,4 @@
ed60a4e9dd35dcabb9b24e90434f5f615d988981 jdk9-b26
221a84ef44c00335b563d92f470efaf8162b471e jdk9-b27
00c31e5eaf26f9b238165157b9d1c617b03abcb6 jdk9-b28
+e541ebaf2ab7038333ad0c13f4decd327c26dd15 jdk9-b29
--- a/nashorn/bin/dump_octane_code.sh Thu Sep 04 13:26:26 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-#!/bin/bash
-# Copyright (c) 2010, 2013, 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.
-#
-
-#
-# The purpose of this script is to provide a large amount of IR/bytecode from a known
-# application to be diffed against the same output with a different Nashorn version.
-# That way we can quickly detect if a seemingly minute change modifies a lot of code,
-# which it most likely shouldn't. One example of this was when AccessSpecializer was
-# moved into Lower the first time, it worked fine, but as a lot of Scope information
-# at the time was finalized further down the code pipeline it did a lot fewer callsite
-# specializations. This would have been immediately detected with a before and after
-# diff using the output from this script.
-#
-
-ITERS=$1
-if [ -z $ITERS ]; then
- ITERS=7
-fi
-NASHORN_JAR=dist/nashorn.jar
-JVM_FLAGS="-ea -esa -server -jar ${NASHORN_JAR}"
-
-BENCHMARKS=( "box2d.js" "code-load.js" "crypto.js" "deltablue.js" "earley-boyer.js" "gbemu.js" "mandreel.js" "navier-stokes.js" "pdfjs.js" "raytrace.js" "regexp.js" "richards.js" "splay.js" )
-
-for BENCHMARK in "${BENCHMARKS[@]}"
-do
- echo "START: ${BENCHMARK}"
- CMD="${JAVA_HOME}/bin/java ${JVM_FLAGS} -co --print-lower-parse test/script/external/octane/${BENCHMARK}"
- $CMD
- echo "END: ${BENCHMARK}"
- echo ""
-done
-
-echo "Done"
--- a/nashorn/bin/fixorphantests.sh Thu Sep 04 13:26:26 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2010, 2013, 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.
-#
-
-#ensure that all tests tagged with @test are also tagged with @run
-
-for f in $(find test/script/basic/*.js); do
- grep @test $f >/dev/null
- TEST=$?
- grep @run $f >/dev/null
- RUN=$?
-
- if [ $TEST -eq 0 ] && [ ! $RUN -eq 0 ]; then
- echo "repairing ${f}..."
- TEMP=$(mktemp /tmp/scratch.XXXXXX)
-
- #IFS='', -raw flag to preserve white space
- while IFS='' read -r line; do
- echo $line | grep @test >/dev/null
- TEST=$?
- printf "%s\n" "$line"
- if [ $TEST -eq 0 ]; then
- printf "%s\n" "$line" | sed s/@test/@run/g
- fi
- done < $f >$TEMP
-
- cp $TEMP $f
-
- rm -fr $TEMP
- fi
-
-done
--- a/nashorn/bin/fixwhitespace.sh Thu Sep 04 13:26:26 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2010, 2013, 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.
-#
-
-fix() {
- #convert tabs to spaces
- find . -name $1 -exec sed -i "" 's/ / /g' {} \;
- #remove trailing whitespace
- find . -name $1 -exec sed -i "" 's/[ ]*$//' \{} \;
-}
-
-if [ ! -z $1 ]; then
- fix $1;
-else
- fix "*.java"
- fix "*.js"
-fi
--- a/nashorn/bin/jjsdebug.sh Thu Sep 04 13:26:26 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2014, 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.
-#
-
-$JAVA_HOME/bin/jjs -J-Djava.ext.dirs=`dirname $0`/../dist -J-agentlib:jdwp=transport=dt_socket,address=localhost:9009,server=y,suspend=y $*
--- a/nashorn/bin/rm-non-tracked.sh Thu Sep 04 13:26:26 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2010, 2013, 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.
-#
-hg status|grep ^\?|awk '{print $2}'|xargs rm
--- a/nashorn/bin/run_octane.sh Thu Sep 04 13:26:26 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2010, 2014, 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.
-#
-
-LOG="./octane_$(date|sed "s/ /_/g"|sed "s/:/_/g").log"
-
-run_one() {
- sh ../bin/runopt.sh -scripting ../test/script/basic/run-octane.js -- $1 --verbose --iterations 25 | tee -a $LOG
-}
-
-if [ -z $1 ]; then
-
- run_one "box2d"
- run_one "code-load"
- run_one "crypto"
- run_one "deltablue"
- run_one "earley-boyer"
- run_one "gbemu"
- run_one "mandreel"
- run_one "navier-stokes"
- run_one "pdfjs"
- run_one "raytrace"
- run_one "regexp"
- run_one "richards"
- run_one "splay"
- run_one "typescript"
- run_one "zlib"
-
-else
- run_one $1
-fi
--- a/nashorn/bin/rundiff.sh Thu Sep 04 13:26:26 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#!/bin/sh
-
-# do two runs of a script, one optimistic and one pessimistic, expect identical outputs
-# if not, display and error message and a diff
-
-which opendiff >/dev/null
-RES=$?
-if [ $RES = 0 ]; then
- DIFFTOOL=opendiff
-else
- DIFFTOOL=diff
-fi
-
-OPTIMISTIC=out_optimistic
-PESSIMISTIC=out_pessimistic
-$JAVA_HOME/bin/java -ea -jar ../dist/nashorn.jar ${@} >$PESSIMISTIC
-$JAVA_HOME/bin/java -ea -Dnashorn.optimistic -jar ../dist/nashorn.jar ${@} >$OPTIMISTIC
-
-if ! diff -q $PESSIMISTIC $OPTIMISTIC >/dev/null ; then
- echo "Failure! Results are different"
- echo ""
- $DIFFTOOL $PESSIMISTIC $OPTIMISTIC
-else
- echo "OK - Results are identical"
-fi
--- a/nashorn/bin/runopt.sh Thu Sep 04 13:26:26 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2010, 2014, 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.
-#
-
-###########################################################################################
-# This is a helper script to evaluate nashorn with optimistic types
-# it produces a flight recording for every run, and uses the best
-# known flags for performance for the current configration
-###########################################################################################
-
-# Flags to instrument lambdaform computation, caching, interpretation and compilation
-# Default compile threshold for lambdaforms is 30
-#FLAGS="-Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=3 -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true -Djava.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE=true -Djava.lang.invoke.MethodHandle.TRACE_INTERPRETER=true"
-
-
-# Flags to run trusted tests from the Nashorn test suite
-#FLAGS="-Djava.security.manager -Djava.security.policy=../build/nashorn.policy -Dnashorn.debug"
-
-
-# Unique timestamped file name for JFR recordings. For JFR, we also have to
-# crank up the stack cutoff depth to 1024, because of ridiculously long lambda form
-# stack traces.
-#
-# It is also recommended that you go into $JAVA_HOME/jre/lib/jfr/default.jfc and
-# set the "method-sampling-interval" Normal and Maximum sample time as low as you
-# can go (10 ms on most platforms). The default is normally higher. The increased
-# sampling overhead is usually negligible for Nashorn runs, but the data is better
-
-JFR_FILENAME="./nashorn_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
-
-
-# Directory where to look for nashorn.jar in a dist folder. The default is "..", assuming
-# that we run the script from the make dir
-DIR=..
-NASHORN_JAR=$DIR/dist/nashorn.jar
-
-
-# The built Nashorn jar is placed first in the bootclasspath to override the JDK
-# nashorn.jar in $JAVA_HOME/jre/lib/ext. Thus, we also need -esa, as assertions in
-# nashorn count as system assertions in this configuration
-
-# Type profiling default level is 111, 222 adds some compile time, but is faster
-
-$JAVA_HOME/bin/java \
-$FLAGS \
--ea \
--esa \
--Xbootclasspath/p:$NASHORN_JAR \
--Xms2G -Xmx2G \
--XX:TypeProfileLevel=222 \
--cp $CLASSPATH:../build/test/classes/ \
-jdk.nashorn.tools.Shell ${@}
-
-# Below are flags that may come in handy, but aren't used for default runs
-
-# Testing out new code optimizations using the generic hotspot "new code" parameter
-#-XX:+UnlockDiagnosticVMOptions \
-#-XX:+UseNewCode \
-
-# Flight recorder
-#-XX:+UnlockCommercialFeatures \
-#-XX:+FlightRecorder \
-#-XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$JFR_FILENAME,stackdepth=1024 \
-
-
-# Type specialization and math intrinsic replacement should be enabled by default in 8u20 and nine,
-# keeping this flag around for experimental reasons. Replace + with - to switch it off
-#-XX:+UseTypeSpeculation \
-
-
-# Same with math intrinsics. They should be enabled by default in 8u20 and 9
-#-XX:+UseMathExactIntrinsics \
-
-
-# Add -Dnashorn.time to time the compilation phases.
-#-Dnashorn.time \
-
-
-# Add ShowHiddenFrames to get lambda form internals on the stack traces
-#-XX:+ShowHiddenFrames \
-
-
-# Add print optoassembly to get an asm dump. This requires 1) a debug build, not product,
-# That tired compilation is switched off, for C2 only output and that the number of
-# compiler threads is set to 1 for determinsm.
-#-XX:+PrintOptoAssembly -XX:-TieredCompilation -XX:CICompilerCount=1 \
-
-# Tier compile threasholds. Default value is 10. (1-100 is useful for experiments)
-# -XX:IncreaseFirstTierCompileThresholdAt=XX
-
--- a/nashorn/bin/runopt_noassert.sh Thu Sep 04 13:26:26 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-#!/bin/sh
-
-#FLAGS="-Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=3 -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true -Djava.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE=true -Djava.lang.invoke.MethodHandle.TRACE_INTERPRETER=true"
-
-FILENAME="./optimistic_noassert_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
-
-DIR=..
-NASHORN_JAR=$DIR/dist/nashorn.jar
-
-$JAVA_HOME/bin/java \
-$FLAGS \
--Xbootclasspath/p:$NASHORN_JAR \
--Xms2G -Xmx2G \
--XX:+UnlockCommercialFeatures \
--XX:+FlightRecorder \
--XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$FILENAME,stackdepth=1024 \
--XX:TypeProfileLevel=222 \
--XX:+UnlockExperimentalVMOptions \
--XX:+UseTypeSpeculation \
--XX:+UseMathExactIntrinsics \
--XX:+UnlockDiagnosticVMOptions \
--cp $CLASSPATH:../build/test/classes/ \
-jdk.nashorn.tools.Shell ${@}
-
-#-XX:+ShowHiddenFrames \
-#-XX:+PrintOptoAssembly \
-#-XX:-TieredCompilation \
-#-XX:CICompilerCount=1 \
--- a/nashorn/bin/runopt_nojfr.sh Thu Sep 04 13:26:26 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-#!/bin/sh
-
-#FLAGS="-Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=3 -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true -Djava.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE=true -Djava.lang.invoke.MethodHandle.TRACE_INTERPRETER=true"
-
-DIR=..
-NASHORN_JAR=$DIR/dist/nashorn.jar
-
-$JAVA_HOME/bin/java \
-$FLAGS \
--ea \
--esa \
--Xbootclasspath/p:$NASHORN_JAR \
--Xms2G -Xmx2G \
--XX:+UnlockCommercialFeatures \
--XX:TypeProfileLevel=222 \
--XX:+UnlockExperimentalVMOptions \
--XX:+UseTypeSpeculation \
--XX:+UseMathExactIntrinsics \
--XX:+UnlockDiagnosticVMOptions \
--XX:+UseNewCode \
--cp $CLASSPATH:../build/test/classes/ \
-jdk.nashorn.tools.Shell ${@}
-
-#-XX:+ShowHiddenFrames \
-#-XX:+PrintOptoAssembly \
-#-XX:-TieredCompilation \
-#-XX:CICompilerCount=1 \
--- a/nashorn/make/build.xml Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/make/build.xml Wed Jul 05 19:59:54 2017 +0200
@@ -341,6 +341,13 @@
permission java.util.PropertyPermission "nashorn.test.*", "read";
};
+grant codeBase "file:/${basedir}/test/script/basic/es6/*" {
+ permission java.io.FilePermission "${basedir}/test/script/-", "read";
+ permission java.io.FilePermission "$${user.dir}", "read";
+ permission java.util.PropertyPermission "user.dir", "read";
+ permission java.util.PropertyPermission "nashorn.test.*", "read";
+};
+
grant codeBase "file:/${basedir}/test/script/basic/JDK-8010946-privileged.js" {
permission java.util.PropertyPermission "java.security.policy", "read";
};
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java Wed Jul 05 19:59:54 2017 +0200
@@ -36,6 +36,7 @@
import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
import static jdk.nashorn.internal.ir.Symbol.HAS_OBJECT_VALUE;
+import static jdk.nashorn.internal.ir.Symbol.IS_CONST;
import static jdk.nashorn.internal.ir.Symbol.IS_FUNCTION_SELF;
import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL;
import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
@@ -83,11 +84,13 @@
import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WithNode;
-import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Context;
-import jdk.nashorn.internal.runtime.Property;
-import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.ECMAErrors;
+import jdk.nashorn.internal.runtime.ErrorManager;
+import jdk.nashorn.internal.runtime.JSErrorType;
+import jdk.nashorn.internal.runtime.ParserException;
+import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
import jdk.nashorn.internal.runtime.logging.Loggable;
import jdk.nashorn.internal.runtime.logging.Logger;
@@ -101,7 +104,7 @@
* visitor.
*/
@Logger(name="symbols")
-final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements Loggable {
+final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggable {
private final DebugLogger log;
private final boolean debug;
@@ -190,8 +193,7 @@
* @param body the body of the FunctionNode we are entering
*/
private void acceptDeclarations(final FunctionNode functionNode, final Block body) {
- // This visitor will assign symbol to all declared variables, except function declarations (which are taken care
- // in a separate step above) and "var" declarations in for loop initializers.
+ // This visitor will assign symbol to all declared variables, except "var" declarations in for loop initializers.
//
body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
@@ -204,8 +206,8 @@
public Node leaveVarNode(final VarNode varNode) {
if (varNode.isStatement()) {
final IdentNode ident = varNode.getName();
- final Symbol symbol = defineSymbol(body, ident.getName(), IS_VAR);
- functionNode.addDeclaredSymbol(symbol);
+ final Block block = varNode.isBlockScoped() ? getLexicalContext().getCurrentBlock() : body;
+ final Symbol symbol = defineSymbol(block, ident.getName(), ident, varNode.getSymbolFlags());
if (varNode.isFunctionDeclaration()) {
symbol.setIsFunctionDeclaration();
}
@@ -303,23 +305,31 @@
return functionNode.setBody(lc, body.setStatements(lc, newStatements));
}
- private Symbol defineGlobalSymbol(final Block block, final String name) {
- return defineSymbol(block, name, IS_GLOBAL);
- }
-
/**
* Defines a new symbol in the given block.
*
* @param block the block in which to define the symbol
* @param name name of symbol.
+ * @param origin origin node
* @param symbolFlags Symbol flags.
*
* @return Symbol for given name or null for redefinition.
*/
- private Symbol defineSymbol(final Block block, final String name, final int symbolFlags) {
+ private Symbol defineSymbol(final Block block, final String name, final Node origin, final int symbolFlags) {
int flags = symbolFlags;
- Symbol symbol = findSymbol(block, name); // Locate symbol.
- final boolean isGlobal = (flags & KINDMASK) == IS_GLOBAL;
+ final boolean isBlockScope = (flags & IS_LET) != 0 || (flags & IS_CONST) != 0;
+ final boolean isGlobal = (flags & KINDMASK) == IS_GLOBAL;
+
+ Symbol symbol;
+ final FunctionNode function;
+ if (isBlockScope) {
+ // block scoped variables always live in current block, no need to look for existing symbols in parent blocks.
+ symbol = block.getExistingSymbol(name);
+ function = lc.getCurrentFunction();
+ } else {
+ symbol = findSymbol(block, name);
+ function = lc.getFunction(block);
+ }
// Global variables are implicitly always scope variables too.
if (isGlobal) {
@@ -333,7 +343,6 @@
final boolean isParam = (flags & KINDMASK) == IS_PARAM;
final boolean isVar = (flags & KINDMASK) == IS_VAR;
- final FunctionNode function = lc.getFunction(block);
if (symbol != null) {
// Symbol was already defined. Check if it needs to be redefined.
if (isParam) {
@@ -345,10 +354,21 @@
throw new AssertionError("duplicate parameter");
}
} else if (isVar) {
- if ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET) {
+ if (isBlockScope) {
+ // Check redeclaration in same block
+ if (symbol.hasBeenDeclared()) {
+ throwParserException(ECMAErrors.getMessage("syntax.error.redeclare.variable", name), origin);
+ } else {
+ symbol.setHasBeenDeclared();
+ }
+ } else if ((flags & IS_INTERNAL) != 0) {
// Always create a new definition.
symbol = null;
} else {
+ // Found LET or CONST in parent scope of same function - s SyntaxError
+ if (symbol.isBlockScoped() && isLocal(lc.getCurrentFunction(), symbol)) {
+ throwParserException(ECMAErrors.getMessage("syntax.error.redeclare.variable", name), origin);
+ }
// Not defined in this function. Create a new definition.
if (!isLocal(function, symbol) || symbol.less(IS_VAR)) {
symbol = null;
@@ -359,10 +379,10 @@
if (symbol == null) {
// If not found, then create a new one.
- Block symbolBlock;
+ final Block symbolBlock;
// Determine where to create it.
- if (isVar && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) {
+ if (isVar && ((flags & IS_INTERNAL) != 0 || isBlockScope)) {
symbolBlock = block; //internal vars are always defined in the block closest to them
} else if (isGlobal) {
symbolBlock = lc.getOutermostFunction().getBody();
@@ -420,9 +440,9 @@
@Override
public boolean enterBlock(final Block block) {
start(block);
- block.clearSymbols();
if (lc.isFunctionBody()) {
+ block.clearSymbols();
enterFunctionBody();
}
@@ -441,7 +461,10 @@
// If the name of the exception starts with ":e", this is a synthetic catch block, likely a catch-all. Its
// symbol is naturally internal, and should be treated as such.
final boolean isInternal = exname.startsWith(EXCEPTION_PREFIX.symbolName());
- defineSymbol(block, exname, IS_VAR | IS_LET | (isInternal ? IS_INTERNAL : 0) | HAS_OBJECT_VALUE);
+ // IS_LET flag is required to make sure symbol is not visible outside catch block. However, we need to
+ // clear the IS_LET flag after creation to allow redefinition of symbol inside the catch block.
+ final Symbol symbol = defineSymbol(block, exname, catchNode, IS_VAR | IS_LET | (isInternal ? IS_INTERNAL : 0) | HAS_OBJECT_VALUE);
+ symbol.clearFlag(IS_LET);
return true;
}
@@ -452,15 +475,13 @@
initFunctionWideVariables(functionNode, body);
- if (functionNode.isProgram()) {
- initGlobalSymbols(body);
- } else if (!functionNode.isDeclared() && !functionNode.isAnonymous()) {
+ if (!functionNode.isProgram() && !functionNode.isDeclared() && !functionNode.isAnonymous()) {
// It's neither declared nor program - it's a function expression then; assign it a self-symbol unless it's
// anonymous.
final String name = functionNode.getIdent().getName();
assert name != null;
assert body.getExistingSymbol(name) == null;
- defineSymbol(body, name, IS_VAR | IS_FUNCTION_SELF | HAS_OBJECT_VALUE);
+ defineSymbol(body, name, functionNode, IS_VAR | IS_FUNCTION_SELF | HAS_OBJECT_VALUE);
if(functionNode.allVarsInScope()) { // basically, has deep eval
lc.setFlag(functionNode, FunctionNode.USES_SELF_SYMBOL);
}
@@ -485,7 +506,8 @@
if (functionNode.isDeclared()) {
final Iterator<Block> blocks = lc.getBlocks();
if (blocks.hasNext()) {
- defineSymbol(blocks.next(), functionNode.getIdent().getName(), IS_VAR | (functionNode.isAnonymous()? IS_INTERNAL : 0));
+ final IdentNode ident = functionNode.getIdent();
+ defineSymbol(blocks.next(), ident.getName(), ident, IS_VAR | (functionNode.isAnonymous()? IS_INTERNAL : 0));
}
}
@@ -495,10 +517,16 @@
@Override
public boolean enterVarNode(final VarNode varNode) {
start(varNode);
- defineSymbol(lc.getCurrentBlock(), varNode.getName().getName(), IS_VAR | (lc.getCurrentFunction().isProgram() ? IS_SCOPE : 0));
return true;
}
+ @Override
+ public Node leaveVarNode(final VarNode varNode) {
+ final IdentNode ident = varNode.getName();
+ defineSymbol(lc.getCurrentBlock(), ident.getName(), ident, varNode.getSymbolFlags() | (lc.getCurrentFunction().isProgram() ? IS_SCOPE : 0));
+ return super.leaveVarNode(varNode);
+ }
+
private Symbol exceptionSymbol() {
return newObjectInternal(EXCEPTION_PREFIX);
}
@@ -597,7 +625,7 @@
}
private void initCompileConstant(final CompilerConstants cc, final Block block, final int flags) {
- defineSymbol(block, cc.symbolName(), flags).setNeedsSlot(true);
+ defineSymbol(block, cc.symbolName(), null, flags).setNeedsSlot(true);
}
private void initFunctionWideVariables(final FunctionNode functionNode, final Block body) {
@@ -608,7 +636,7 @@
initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL | HAS_OBJECT_VALUE);
if (functionNode.needsArguments()) {
initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL | HAS_OBJECT_VALUE);
- defineSymbol(body, ARGUMENTS_VAR.symbolName(), IS_VAR | HAS_OBJECT_VALUE);
+ defineSymbol(body, ARGUMENTS_VAR.symbolName(), null, IS_VAR | HAS_OBJECT_VALUE);
}
}
@@ -617,20 +645,6 @@
initCompileConstant(RETURN, body, IS_VAR | IS_INTERNAL);
}
-
- /**
- * Move any properties from the global map into the scope of this function (which must be a program function).
- * @param block the function node body for which to init scope vars
- */
- private void initGlobalSymbols(final Block block) {
- final PropertyMap map = Context.getGlobalMap();
-
- for (final Property property : map.getProperties()) {
- final Symbol symbol = defineGlobalSymbol(block, property.getKey());
- log.info("Added global symbol from property map ", symbol);
- }
- }
-
/**
* Initialize parameters for function node.
* @param functionNode the function node
@@ -639,7 +653,7 @@
final boolean isVarArg = functionNode.isVarArg();
final boolean scopeParams = functionNode.allVarsInScope() || isVarArg;
for (final IdentNode param : functionNode.getParameters()) {
- final Symbol symbol = defineSymbol(body, param.getName(), IS_PARAM);
+ final Symbol symbol = defineSymbol(body, param.getName(), param, IS_PARAM);
if(scopeParams) {
// NOTE: this "set is scope" is a poor substitute for clear expression of where the symbol is stored.
// It will force creation of scopes where they would otherwise not necessarily be needed (functions
@@ -665,10 +679,29 @@
return definingFn == function;
}
+ private void checkConstAssignment(final IdentNode ident) {
+ // Check for reassignment of constant
+ final Symbol symbol = ident.getSymbol();
+ if (symbol.isConst()) {
+ throwParserException(ECMAErrors.getMessage("syntax.error.assign.constant", symbol.getName()), ident);
+ }
+ }
+
@Override
- public Node leaveASSIGN(final BinaryNode binaryNode) {
+ public Node leaveBinaryNode(final BinaryNode binaryNode) {
+ if (binaryNode.isAssignment() && binaryNode.lhs() instanceof IdentNode) {
+ checkConstAssignment((IdentNode) binaryNode.lhs());
+ }
+ switch (binaryNode.tokenType()) {
+ case ASSIGN:
+ return leaveASSIGN(binaryNode);
+ default:
+ return super.leaveBinaryNode(binaryNode);
+ }
+ }
+
+ private Node leaveASSIGN(final BinaryNode binaryNode) {
// If we're assigning a property of the this object ("this.foo = ..."), record it.
-
final Expression lhs = binaryNode.lhs();
if (lhs instanceof AccessNode) {
final AccessNode accessNode = (AccessNode) lhs;
@@ -684,6 +717,21 @@
}
@Override
+ public Node leaveUnaryNode(final UnaryNode unaryNode) {
+ if (unaryNode.isAssignment() && unaryNode.getExpression() instanceof IdentNode) {
+ checkConstAssignment((IdentNode) unaryNode.getExpression());
+ }
+ switch (unaryNode.tokenType()) {
+ case DELETE:
+ return leaveDELETE(unaryNode);
+ case TYPEOF:
+ return leaveTYPEOF(unaryNode);
+ default:
+ return super.leaveUnaryNode(unaryNode);
+ }
+ }
+
+ @Override
public Node leaveBlock(final Block block) {
// It's not necessary to guard the marking of symbols as locals with this "if"condition for correctness, it's
// just an optimization -- runtime type calculation is not used when the compilation is not an on-demand
@@ -699,8 +747,7 @@
return block;
}
- @Override
- public Node leaveDELETE(final UnaryNode unaryNode) {
+ private Node leaveDELETE(final UnaryNode unaryNode) {
final FunctionNode currentFunctionNode = lc.getCurrentFunction();
final boolean strictMode = currentFunctionNode.isStrict();
final Expression rhs = unaryNode.getExpression();
@@ -799,9 +846,8 @@
// if symbol is non-local or we're in a with block, we need to put symbol in scope (if it isn't already)
maybeForceScope(symbol);
} else {
- log.info("No symbol exists. Declare as global: ", symbol);
- symbol = defineGlobalSymbol(block, name);
- Symbol.setSymbolIsScope(lc, symbol);
+ log.info("No symbol exists. Declare as global: ", name);
+ symbol = defineSymbol(block, name, identNode, IS_GLOBAL | IS_SCOPE);
}
functionUsesSymbol(symbol);
@@ -810,7 +856,15 @@
symbol.increaseUseCount();
}
- return end(identNode.setSymbol(symbol));
+ IdentNode newIdentNode = identNode.setSymbol(symbol);
+
+ // If a block-scoped var is used before its declaration mark it as dead.
+ // We can only statically detect this for local vars, cross-function symbols require runtime checks.
+ if (symbol.isBlockScoped() && !symbol.hasBeenDeclared() && !identNode.isDeclaredHere() && isLocal(lc.getCurrentFunction(), symbol)) {
+ newIdentNode = newIdentNode.markDead();
+ }
+
+ return end(newIdentNode);
}
@Override
@@ -834,8 +888,7 @@
return tryNode;
}
- @Override
- public Node leaveTYPEOF(final UnaryNode unaryNode) {
+ private Node leaveTYPEOF(final UnaryNode unaryNode) {
final Expression rhs = unaryNode.getExpression();
final List<Expression> args = new ArrayList<>();
@@ -875,7 +928,7 @@
}
private Symbol newInternal(final CompilerConstants cc, final int flags) {
- return defineSymbol(lc.getCurrentBlock(), lc.getCurrentFunction().uniqueName(cc.symbolName()), IS_VAR | IS_INTERNAL | flags); //NASHORN-73
+ return defineSymbol(lc.getCurrentBlock(), lc.getCurrentFunction().uniqueName(cc.symbolName()), null, IS_VAR | IS_INTERNAL | flags); //NASHORN-73
}
private Symbol newObjectInternal(final CompilerConstants cc) {
@@ -915,7 +968,8 @@
return false;
}
- if (lc.getCurrentFunction().allVarsInScope()) {
+ final FunctionNode func = lc.getCurrentFunction();
+ if ( func.allVarsInScope() || (!symbol.isBlockScoped() && func.isProgram())) {
return true;
}
@@ -955,4 +1009,16 @@
final List<ArrayUnit> units = ((ArrayLiteralNode)expr).getUnits();
return !(units == null || units.isEmpty());
}
+
+ private void throwParserException(final String message, final Node origin) {
+ if (origin == null) {
+ throw new ParserException(message);
+ }
+ final Source source = compiler.getSource();
+ final long token = origin.getToken();
+ final int line = source.getLine(origin.getStart());
+ final int column = source.getColumn(origin.getStart());
+ final String formatted = ErrorManager.format(message, source, line, column, token);
+ throw new ParserException(JSErrorType.SYNTAX_ERROR, formatted, source, line, column, token);
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Jul 05 19:59:54 2017 +0200
@@ -52,6 +52,7 @@
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_APPLY_TO_CALL;
+import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_DECLARE;
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_FAST_SCOPE;
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_OPTIMISTIC;
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_PROGRAM_POINT_SHIFT;
@@ -302,6 +303,7 @@
* @return the method generator used
*/
private MethodEmitter loadIdent(final IdentNode identNode, final TypeBounds resultBounds) {
+ checkTemporalDeadZone(identNode);
final Symbol symbol = identNode.getSymbol();
if (!symbol.isScope()) {
@@ -334,6 +336,15 @@
return method;
}
+ // Any access to LET and CONST variables before their declaration must throw ReferenceError.
+ // This is called the temporal dead zone (TDZ). See https://gist.github.com/rwaldron/f0807a758aa03bcdd58a
+ private void checkTemporalDeadZone(final IdentNode identNode) {
+ if (identNode.isDead()) {
+ method.load(identNode.getSymbol().getName());
+ method.invoke(ScriptRuntime.THROW_REFERENCE_ERROR);
+ }
+ }
+
private boolean isRestOf() {
return continuationEntryPoints != null;
}
@@ -3216,27 +3227,34 @@
return false;
}
final Expression init = varNode.getInit();
+ final IdentNode identNode = varNode.getName();
+ final Symbol identSymbol = identNode.getSymbol();
+ assert identSymbol != null : "variable node " + varNode + " requires a name with a symbol";
+ final boolean needsScope = identSymbol.isScope();
if (init == null) {
+ if (needsScope && varNode.isBlockScoped()) {
+ // block scoped variables need a DECLARE flag to signal end of temporal dead zone (TDZ)
+ method.loadCompilerConstant(SCOPE);
+ method.loadUndefined(Type.OBJECT);
+ final int flags = CALLSITE_SCOPE | getCallSiteFlags() | (varNode.isBlockScoped() ? CALLSITE_DECLARE : 0);
+ assert isFastScope(identSymbol);
+ storeFastScopeVar(identSymbol, flags);
+ }
return false;
}
enterStatement(varNode);
-
- final IdentNode identNode = varNode.getName();
- final Symbol identSymbol = identNode.getSymbol();
- assert identSymbol != null : "variable node " + varNode + " requires a name with a symbol";
-
assert method != null;
- final boolean needsScope = identSymbol.isScope();
if (needsScope) {
method.loadCompilerConstant(SCOPE);
}
if (needsScope) {
loadExpressionUnbounded(init);
- final int flags = CALLSITE_SCOPE | getCallSiteFlags();
+ // block scoped variables need a DECLARE flag to signal end of temporal dead zone (TDZ)
+ final int flags = CALLSITE_SCOPE | getCallSiteFlags() | (varNode.isBlockScoped() ? CALLSITE_DECLARE : 0);
if (isFastScope(identSymbol)) {
storeFastScopeVar(identSymbol, flags);
} else {
@@ -4343,6 +4361,9 @@
protected abstract void evaluate();
void store() {
+ if (target instanceof IdentNode) {
+ checkTemporalDeadZone((IdentNode)target);
+ }
prologue();
evaluate(); // leaves an operation of whatever the operationType was on the stack
storeNonDiscard();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java Wed Jul 05 19:59:54 2017 +0200
@@ -59,7 +59,9 @@
import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator;
import jdk.nashorn.internal.runtime.CodeInstaller;
import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.ErrorManager;
import jdk.nashorn.internal.runtime.FunctionInitializer;
+import jdk.nashorn.internal.runtime.ParserException;
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.ScriptObject;
@@ -89,6 +91,8 @@
private final String sourceName;
+ private final ErrorManager errors;
+
private final boolean optimistic;
private final Map<String, byte[]> bytecode;
@@ -311,6 +315,7 @@
* @param env script environment
* @param installer code installer
* @param source source to compile
+ * @param errors error manager
* @param isStrict is this a strict compilation
*/
public Compiler(
@@ -318,8 +323,9 @@
final ScriptEnvironment env,
final CodeInstaller<ScriptEnvironment> installer,
final Source source,
+ final ErrorManager errors,
final boolean isStrict) {
- this(context, env, installer, source, isStrict, false, null, null, null, null, null, null);
+ this(context, env, installer, source, errors, isStrict, false, null, null, null, null, null, null);
}
/**
@@ -329,6 +335,7 @@
* @param env script environment
* @param installer code installer
* @param source source to compile
+ * @param errors error manager
* @param isStrict is this a strict compilation
* @param isOnDemand is this an on demand compilation
* @param compiledFunction compiled function, if any
@@ -343,6 +350,7 @@
final ScriptEnvironment env,
final CodeInstaller<ScriptEnvironment> installer,
final Source source,
+ final ErrorManager errors,
final boolean isStrict,
final boolean isOnDemand,
final RecompilableScriptFunctionData compiledFunction,
@@ -359,6 +367,7 @@
this.bytecode = new LinkedHashMap<>();
this.log = initLogger(context);
this.source = source;
+ this.errors = errors;
this.sourceName = FunctionNode.getSourceName(source);
this.onDemand = isOnDemand;
this.compiledFunction = compiledFunction;
@@ -524,7 +533,17 @@
for (final CompilationPhase phase : phases) {
log.fine(phase, " starting for ", quote(name));
- newFunctionNode = phase.apply(this, phases, newFunctionNode);
+
+ try {
+ newFunctionNode = phase.apply(this, phases, newFunctionNode);
+ } catch (final ParserException error) {
+ errors.error(error);
+ if (env._dump_on_error) {
+ error.printStackTrace(env.getErr());
+ }
+ return null;
+ }
+
log.fine(phase, " done for function ", quote(name));
if (env._print_mem_usage) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/DumpBytecode.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/DumpBytecode.java Wed Jul 05 19:59:54 2017 +0200
@@ -89,7 +89,7 @@
// should code be dumped to disk - only valid in compile_only mode?
- if (env._dest_dir != null && env._compile_only) {
+ if (env._dest_dir != null) {
final String fileName = className.replace('.', File.separatorChar) + ".class";
final int index = fileName.lastIndexOf(File.separatorChar);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java Wed Jul 05 19:59:54 2017 +0200
@@ -69,9 +69,7 @@
* Constructor
*
* @param codegen code generator
- * @param keys keys for fields in object
- * @param symbols symbols for fields in object
- * @param values list of values corresponding to keys
+ * @param tuples tuples for fields in object
*/
FieldObjectCreator(final CodeGenerator codegen, final List<MapTuple<T>> tuples) {
this(codegen, tuples, false, false);
@@ -81,9 +79,7 @@
* Constructor
*
* @param codegen code generator
- * @param keys keys for fields in object
- * @param symbols symbols for fields in object
- * @param values values (or null where no value) to be written to the fields
+ * @param tuples tuples for fields in object
* @param isScope is this a scope object
* @param hasArguments does the created object have an "arguments" property
*/
@@ -165,7 +161,7 @@
* @param method Script method.
* @param key Property key.
* @param fieldIndex Field number.
- * @param value Value to store.
+ * @param tuple Tuple to store.
*/
private void putField(final MethodEmitter method, final String key, final int fieldIndex, final MapTuple<T> tuple) {
method.dup();
@@ -188,7 +184,7 @@
*
* @param method Script method.
* @param index Slot index.
- * @param value Value to store.
+ * @param tuple Tuple to store.
*/
private void putSlot(final MethodEmitter method, final long index, final MapTuple<T> tuple) {
method.dup();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MapCreator.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MapCreator.java Wed Jul 05 19:59:54 2017 +0200
@@ -52,8 +52,7 @@
* Constructor
*
* @param structure structure to generate map for (a JO subclass)
- * @param keys list of keys for map
- * @param symbols list of symbols for map
+ * @param tuples list of tuples for map
*/
MapCreator(final Class<? extends ScriptObject> structure, final List<MapTuple<T>> tuples) {
this.structure = structure;
@@ -149,6 +148,15 @@
flags |= Property.IS_FUNCTION_DECLARATION;
}
+ if (symbol.isConst()) {
+ flags |= Property.NOT_WRITABLE;
+ }
+
+ // Mark symbol as needing declaration. Access before declaration will throw a ReferenceError.
+ if (symbol.isBlockScoped() && symbol.isScope()) {
+ flags |= Property.NEEDS_DECLARATION;
+ }
+
return flags;
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java Wed Jul 05 19:59:54 2017 +0200
@@ -2233,9 +2233,8 @@
/**
* Generate dynamic setter. Pop receiver and property from stack.
*
- * @param valueType the type of the value to set
- * @param name name of property
- * @param flags call site flags
+ * @param name name of property
+ * @param flags call site flags
*/
void dynamicSet(final String name, final int flags) {
assert !isOptimistic(flags);
@@ -2462,7 +2461,6 @@
* Register line number at a label
*
* @param line line number
- * @param label label
*/
void lineNumber(final int line) {
if (context.getEnv()._debug_lines) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java Wed Jul 05 19:59:54 2017 +0200
@@ -31,9 +31,11 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
+import java.nio.file.Path;
import java.security.AccessController;
import java.security.MessageDigest;
import java.security.PrivilegedAction;
@@ -41,6 +43,14 @@
import java.util.Base64;
import java.util.Date;
import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Function;
+import java.util.function.IntFunction;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
@@ -49,30 +59,66 @@
import jdk.nashorn.internal.runtime.options.Options;
/**
- * Static utility that encapsulates persistence of decompilation information for functions. Normally, the type info
- * persistence feature is enabled and operates in an operating-system specific per-user cache directory. You can
- * override the directory by specifying it in the {@code nashorn.typeInfo.cacheDir} directory. Also, you can disable the
- * type info persistence altogether by specifying the {@code nashorn.typeInfo.disabled} system property.
+ * Static utility that encapsulates persistence of type information for functions compiled with optimistic
+ * typing. With this feature enabled, when a JavaScript function is recompiled because it gets deoptimized,
+ * the type information for deoptimization is stored in a cache file. If the same function is compiled in a
+ * subsequent JVM invocation, the type information is used for initial compilation, thus allowing the system
+ * to skip a lot of intermediate recompilations and immediately emit a version of the code that has its
+ * optimistic types at (or near) the steady state.
+ * </p><p>
+ * Normally, the type info persistence feature is disabled. When the {@code nashorn.typeInfo.maxFiles} system
+ * property is specified with a value greater than 0, it is enabled and operates in an operating-system
+ * specific per-user cache directory. You can override the directory by specifying it in the
+ * {@code nashorn.typeInfo.cacheDir} directory. The maximum number of files is softly enforced by a task that
+ * cleans up the directory periodically on a separate thread. It is run after some delay after a new file is
+ * added to the cache. The default delay is 20 seconds, and can be set using the
+ * {@code nashorn.typeInfo.cleanupDelaySeconds} system property. You can also specify the word
+ * {@code unlimited} as the value for {@code nashorn.typeInfo.maxFiles} in which case the type info cache is
+ * allowed to grow without limits.
*/
public final class OptimisticTypesPersistence {
+ // Default is 0, for disabling the feature when not specified. A reasonable default when enabled is
+ // dependent on the application; setting it to e.g. 20000 is probably good enough for most uses and will
+ // usually cap the cache directory to about 80MB presuming a 4kB filesystem allocation unit. There is one
+ // file per JavaScript function.
+ private static final int DEFAULT_MAX_FILES = 0;
+ // Constants for signifying that the cache should not be limited
+ private static final int UNLIMITED_FILES = -1;
+ // Maximum number of files that should be cached on disk. The maximum will be softly enforced.
+ private static final int MAX_FILES = getMaxFiles();
+ // Number of seconds to wait between adding a new file to the cache and running a cleanup process
+ private static final int DEFAULT_CLEANUP_DELAY = 20;
+ private static final int CLEANUP_DELAY = Math.max(0, Options.getIntProperty(
+ "nashorn.typeInfo.cleanupDelaySeconds", DEFAULT_CLEANUP_DELAY));
// The name of the default subdirectory within the system cache directory where we store type info.
private static final String DEFAULT_CACHE_SUBDIR_NAME = "com.oracle.java.NashornTypeInfo";
// The directory where we cache type info
- private static final File cacheDir = createCacheDir();
+ private static final File baseCacheDir = createBaseCacheDir();
+ private static final File cacheDir = createCacheDir(baseCacheDir);
// In-process locks to make sure we don't have a cross-thread race condition manipulating any file.
private static final Object[] locks = cacheDir == null ? null : createLockArray();
-
// Only report one read/write error every minute
private static final long ERROR_REPORT_THRESHOLD = 60000L;
private static volatile long lastReportedError;
-
+ private static final AtomicBoolean scheduledCleanup;
+ private static final Timer cleanupTimer;
+ static {
+ if (baseCacheDir == null || MAX_FILES == UNLIMITED_FILES) {
+ scheduledCleanup = null;
+ cleanupTimer = null;
+ } else {
+ scheduledCleanup = new AtomicBoolean();
+ cleanupTimer = new Timer(true);
+ }
+ }
/**
- * Retrieves an opaque descriptor for the persistence location for a given function. It should be passed to
- * {@link #load(Object)} and {@link #store(Object, Map)} methods.
+ * Retrieves an opaque descriptor for the persistence location for a given function. It should be passed
+ * to {@link #load(Object)} and {@link #store(Object, Map)} methods.
* @param source the source where the function comes from
* @param functionId the unique ID number of the function within the source
- * @param paramTypes the types of the function parameters (as persistence is per parameter type specialization).
+ * @param paramTypes the types of the function parameters (as persistence is per parameter type
+ * specialization).
* @return an opaque descriptor for the persistence location. Can be null if persistence is disabled.
*/
public static Object getLocationDescriptor(final Source source, final int functionId, final Type[] paramTypes) {
@@ -82,7 +128,8 @@
final StringBuilder b = new StringBuilder(48);
// Base64-encode the digest of the source, and append the function id.
b.append(source.getDigest()).append('-').append(functionId);
- // Finally, if this is a parameter-type specialized version of the function, add the parameter types to the file name.
+ // Finally, if this is a parameter-type specialized version of the function, add the parameter types
+ // to the file name.
if(paramTypes != null && paramTypes.length > 0) {
b.append('-');
for(final Type t: paramTypes) {
@@ -118,6 +165,11 @@
@Override
public Void run() {
synchronized(getFileLock(file)) {
+ if (!file.exists()) {
+ // If the file already exists, we aren't increasing the number of cached files, so
+ // don't schedule cleanup.
+ scheduleCleanup();
+ }
try (final FileOutputStream out = new FileOutputStream(file)) {
out.getChannel().lock(); // lock exclusive
final DataOutputStream dout = new DataOutputStream(new BufferedOutputStream(out));
@@ -174,19 +226,19 @@
}
}
- private static File createCacheDir() {
- if(Options.getBooleanProperty("nashorn.typeInfo.disabled")) {
+ private static File createBaseCacheDir() {
+ if(MAX_FILES == 0 || Options.getBooleanProperty("nashorn.typeInfo.disabled")) {
return null;
}
try {
- return createCacheDirPrivileged();
+ return createBaseCacheDirPrivileged();
} catch(final Exception e) {
getLogger().warning("Failed to create cache dir", e);
return null;
}
}
- private static File createCacheDirPrivileged() {
+ private static File createBaseCacheDirPrivileged() {
return AccessController.doPrivileged(new PrivilegedAction<File>() {
@Override
public File run() {
@@ -195,14 +247,35 @@
if(explicitDir != null) {
dir = new File(explicitDir);
} else {
- // When no directory is explicitly specified, get an operating system specific cache directory,
- // and create "com.oracle.java.NashornTypeInfo" in it.
+ // When no directory is explicitly specified, get an operating system specific cache
+ // directory, and create "com.oracle.java.NashornTypeInfo" in it.
final File systemCacheDir = getSystemCacheDir();
dir = new File(systemCacheDir, DEFAULT_CACHE_SUBDIR_NAME);
if (isSymbolicLink(dir)) {
return null;
}
}
+ return dir;
+ }
+ });
+ }
+
+ private static File createCacheDir(final File baseDir) {
+ if (baseDir == null) {
+ return null;
+ }
+ try {
+ return createCacheDirPrivileged(baseDir);
+ } catch(final Exception e) {
+ getLogger().warning("Failed to create cache dir", e);
+ return null;
+ }
+ }
+
+ private static File createCacheDirPrivileged(final File baseDir) {
+ return AccessController.doPrivileged(new PrivilegedAction<File>() {
+ @Override
+ public File run() {
final String versionDirName;
try {
versionDirName = getVersionDirName();
@@ -210,12 +283,12 @@
getLogger().warning("Failed to calculate version dir name", e);
return null;
}
- final File versionDir = new File(dir, versionDirName);
+ final File versionDir = new File(baseDir, versionDirName);
if (isSymbolicLink(versionDir)) {
return null;
}
versionDir.mkdirs();
- if(versionDir.isDirectory()) {
+ if (versionDir.isDirectory()) {
getLogger().info("Optimistic type persistence directory is " + versionDir);
return versionDir;
}
@@ -235,12 +308,12 @@
// Mac OS X stores caches in ~/Library/Caches
return new File(new File(System.getProperty("user.home"), "Library"), "Caches");
} else if(os.startsWith("Windows")) {
- // On Windows, temp directory is the best approximation of a cache directory, as its contents persist across
- // reboots and various cleanup utilities know about it. java.io.tmpdir normally points to a user-specific
- // temp directory, %HOME%\LocalSettings\Temp.
+ // On Windows, temp directory is the best approximation of a cache directory, as its contents
+ // persist across reboots and various cleanup utilities know about it. java.io.tmpdir normally
+ // points to a user-specific temp directory, %HOME%\LocalSettings\Temp.
return new File(System.getProperty("java.io.tmpdir"));
} else {
- // In all other cases we're presumably dealing with a UNIX flavor (Linux, Solaris, etc.); "~/.cache"
+ // In other cases we're presumably dealing with a UNIX flavor (Linux, Solaris, etc.); "~/.cache"
return new File(System.getProperty("user.home"), ".cache");
}
}
@@ -278,7 +351,8 @@
final int packageNameLen = className.lastIndexOf('.');
final String dirStr = fileStr.substring(0, fileStr.length() - packageNameLen - 1);
final File dir = new File(dirStr);
- return "dev-" + new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date(getLastModifiedClassFile(dir, 0L)));
+ return "dev-" + new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date(getLastModifiedClassFile(
+ dir, 0L)));
} else {
throw new AssertionError();
}
@@ -335,4 +409,108 @@
return DebugLogger.DISABLED_LOGGER;
}
}
+
+ private static void scheduleCleanup() {
+ if (MAX_FILES != UNLIMITED_FILES && scheduledCleanup.compareAndSet(false, true)) {
+ cleanupTimer.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ scheduledCleanup.set(false);
+ try {
+ doCleanup();
+ } catch (final IOException e) {
+ // Ignore it. While this is unfortunate, we don't have good facility for reporting
+ // this, as we're running in a thread that has no access to Context, so we can't grab
+ // a DebugLogger.
+ }
+ }
+ }, TimeUnit.SECONDS.toMillis(CLEANUP_DELAY));
+ }
+ }
+
+ private static void doCleanup() throws IOException {
+ final long start = System.nanoTime();
+ final Path[] files = getAllRegularFilesInLastModifiedOrder();
+ final int nFiles = files.length;
+ final int filesToDelete = Math.max(0, nFiles - MAX_FILES);
+ int filesDeleted = 0;
+ for (int i = 0; i < nFiles && filesDeleted < filesToDelete; ++i) {
+ try {
+ Files.deleteIfExists(files[i]);
+ // Even if it didn't exist, we increment filesDeleted; it existed a moment earlier; something
+ // else deleted it for us; that's okay with us.
+ filesDeleted++;
+ } catch (final Exception e) {
+ // does not increase filesDeleted
+ }
+ files[i] = null; // gc eligible
+ };
+ final long duration = System.nanoTime() - start;
+ }
+
+ private static Path[] getAllRegularFilesInLastModifiedOrder() throws IOException {
+ try (final Stream<Path> filesStream = Files.walk(baseCacheDir.toPath())) {
+ // TODO: rewrite below once we can use JDK8 syntactic constructs
+ return filesStream
+ .filter(new Predicate<Path>() {
+ @Override
+ public boolean test(final Path path) {
+ return !Files.isDirectory(path);
+ };
+ })
+ .map(new Function<Path, PathAndTime>() {
+ @Override
+ public PathAndTime apply(final Path path) {
+ return new PathAndTime(path);
+ }
+ })
+ .sorted()
+ .map(new Function<PathAndTime, Path>() {
+ @Override
+ public Path apply(final PathAndTime pathAndTime) {
+ return pathAndTime.path;
+ }
+ })
+ .toArray(new IntFunction<Path[]>() { // Replace with Path::new
+ @Override
+ public Path[] apply(final int length) {
+ return new Path[length];
+ }
+ });
+ }
+ }
+
+ private static class PathAndTime implements Comparable<PathAndTime> {
+ private final Path path;
+ private final long time;
+
+ PathAndTime(final Path path) {
+ this.path = path;
+ this.time = getTime(path);
+ }
+
+ @Override
+ public int compareTo(final PathAndTime other) {
+ return Long.compare(time, other.time);
+ }
+
+ private static long getTime(final Path path) {
+ try {
+ return Files.getLastModifiedTime(path).toMillis();
+ } catch (IOException e) {
+ // All files for which we can't retrieve the last modified date will be considered oldest.
+ return -1L;
+ }
+ }
+ }
+
+ private static int getMaxFiles() {
+ final String str = Options.getStringProperty("nashorn.typeInfo.maxFiles", null);
+ if (str == null) {
+ return DEFAULT_MAX_FILES;
+ } else if ("unlimited".equals(str)) {
+ return UNLIMITED_FILES;
+ }
+ return Math.max(0, Integer.parseInt(str));
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java Wed Jul 05 19:59:54 2017 +0200
@@ -108,7 +108,7 @@
// Safely evaluate the property, and return the narrowest type for the actual value (e.g. Type.INT for a boxed
// integer).
- final Object value = property.getObjectValue(owner, owner);
+ final Object value = property.needsDeclaration() ? ScriptRuntime.UNDEFINED : property.getObjectValue(owner, owner);
if (value == ScriptRuntime.UNDEFINED) {
return null;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/Type.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/Type.java Wed Jul 05 19:59:54 2017 +0200
@@ -333,7 +333,7 @@
*/
public static Map<Integer, Type> readTypeMap(final DataInput input) throws IOException {
final int size = input.readInt();
- if (size == 0) {
+ if (size <= 0) {
return null;
}
final Map<Integer, Type> map = new TreeMap<>();
@@ -345,7 +345,7 @@
case 'L': type = Type.OBJECT; break;
case 'D': type = Type.NUMBER; break;
case 'J': type = Type.LONG; break;
- default: throw new AssertionError();
+ default: continue;
}
map.put(pp, type);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java Wed Jul 05 19:59:54 2017 +0200
@@ -138,10 +138,6 @@
/** Last token of function. **/
private final long lastToken;
- /** Declared symbols in this function node */
- @Ignore
- private final Set<Symbol> declaredSymbols;
-
/** Method's namespace. */
private final Namespace namespace;
@@ -330,7 +326,6 @@
this.lastToken = token;
this.namespace = namespace;
this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
- this.declaredSymbols = new HashSet<>();
this.flags = flags;
this.compileUnit = null;
this.body = null;
@@ -369,7 +364,6 @@
this.id = functionNode.id;
this.ident = functionNode.ident;
this.namespace = functionNode.namespace;
- this.declaredSymbols = functionNode.declaredSymbols;
this.kind = functionNode.kind;
this.firstToken = functionNode.firstToken;
}
@@ -724,24 +718,6 @@
}
/**
- * Return a set of symbols declared in this function node. This
- * is only relevant after Attr, otherwise it will be an empty
- * set as no symbols have been introduced
- * @return set of declared symbols in function
- */
- public Set<Symbol> getDeclaredSymbols() {
- return Collections.unmodifiableSet(declaredSymbols);
- }
-
- /**
- * Add a declared symbol to this function node
- * @param symbol symbol that is declared
- */
- public void addDeclaredSymbol(final Symbol symbol) {
- declaredSymbols.add(symbol);
- }
-
- /**
* Get the function body
* @return the function body
*/
@@ -970,13 +946,13 @@
}
/**
- * Check if this function should have all its variables in its own scope. Scripts, split sub-functions, and
+ * Check if this function should have all its variables in its own scope. Split sub-functions, and
* functions having with and/or eval blocks are such.
*
* @return true if all variables should be in scope
*/
public boolean allVarsInScope() {
- return isProgram() || getFlag(HAS_ALL_VARS_IN_SCOPE);
+ return getFlag(HAS_ALL_VARS_IN_SCOPE);
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java Wed Jul 05 19:59:54 2017 +0200
@@ -46,6 +46,8 @@
private static final int INITIALIZED_HERE = 1 << 1;
private static final int FUNCTION = 1 << 2;
private static final int FUTURESTRICT_NAME = 1 << 3;
+ private static final int IS_DECLARED_HERE = 1 << 4;
+ private static final int IS_DEAD = 1 << 5;
/** Identifier. */
private final String name;
@@ -247,6 +249,45 @@
}
/**
+ * Is this a LET or CONST identifier used before its declaration?
+ *
+ * @return true if identifier is dead
+ */
+ public boolean isDead() {
+ return (flags & IS_DEAD) != 0;
+ }
+
+ /**
+ * Flag this IdentNode as a LET or CONST identifier used before its declaration.
+ *
+ * @return a new IdentNode equivalent to this but marked as dead.
+ */
+ public IdentNode markDead() {
+ return new IdentNode(this, name, type, flags | IS_DEAD, programPoint, conversion);
+ }
+
+ /**
+ * Is this IdentNode declared here?
+ *
+ * @return true if identifier is declared here
+ */
+ public boolean isDeclaredHere() {
+ return (flags & IS_DECLARED_HERE) != 0;
+ }
+
+ /**
+ * Flag this IdentNode as being declared here.
+ *
+ * @return a new IdentNode equivalent to this but marked as declared here.
+ */
+ public IdentNode setIsDeclaredHere() {
+ if (isDeclaredHere()) {
+ return this;
+ }
+ return new IdentNode(this, name, type, flags | IS_DECLARED_HERE, programPoint, conversion);
+ }
+
+ /**
* Check if the name of this IdentNode is same as that of a compile-time property (currently __DIR__, __FILE__, and
* __LINE__).
*
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Symbol.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Symbol.java Wed Jul 05 19:59:54 2017 +0200
@@ -54,17 +54,17 @@
public static final int IS_VAR = 2;
/** Is this a parameter */
public static final int IS_PARAM = 3;
- /** Is this a constant */
- public static final int IS_CONSTANT = 4;
/** Mask for kind flags */
- public static final int KINDMASK = (1 << 3) - 1; // Kinds are represented by lower three bits
+ public static final int KINDMASK = (1 << 2) - 1; // Kinds are represented by lower two bits
/** Is this symbol in scope */
- public static final int IS_SCOPE = 1 << 3;
+ public static final int IS_SCOPE = 1 << 2;
/** Is this a this symbol */
- public static final int IS_THIS = 1 << 4;
+ public static final int IS_THIS = 1 << 3;
/** Is this a let */
- public static final int IS_LET = 1 << 5;
+ public static final int IS_LET = 1 << 4;
+ /** Is this a const */
+ public static final int IS_CONST = 1 << 5;
/** Is this an internal symbol, never represented explicitly in source code */
public static final int IS_INTERNAL = 1 << 6;
/** Is this a function self-reference symbol */
@@ -83,6 +83,8 @@
public static final int HAS_DOUBLE_VALUE = 1 << 13;
/** Is this symbol known to store an object value ? */
public static final int HAS_OBJECT_VALUE = 1 << 14;
+ /** Is this symbol seen a declaration? Used for block scoped LET and CONST symbols only. */
+ public static final int HAS_BEEN_DECLARED = 1 << 15;
/** Null or name identifying symbol. */
private final String name;
@@ -184,14 +186,17 @@
sb.append(" global");
break;
case IS_VAR:
- sb.append(" var");
+ if (isConst()) {
+ sb.append(" const");
+ } else if (isLet()) {
+ sb.append(" let");
+ } else {
+ sb.append(" var");
+ }
break;
case IS_PARAM:
sb.append(" param");
break;
- case IS_CONSTANT:
- sb.append(" const");
- break;
default:
break;
}
@@ -204,10 +209,6 @@
sb.append(" internal");
}
- if (isLet()) {
- sb.append(" let");
- }
-
if (isThis()) {
sb.append(" this");
}
@@ -410,8 +411,8 @@
* Check if this symbol is a constant
* @return true if a constant
*/
- public boolean isConstant() {
- return (flags & KINDMASK) == IS_CONSTANT;
+ public boolean isConst() {
+ return (flags & IS_CONST) != 0;
}
/**
@@ -440,15 +441,6 @@
}
/**
- * Flag this symbol as a let
- */
- public void setIsLet() {
- if (!isLet()) {
- flags |= IS_LET;
- }
- }
-
- /**
* Flag this symbol as a function's self-referencing symbol.
* @return true if this symbol as a function's self-referencing symbol.
*/
@@ -456,6 +448,20 @@
return (flags & IS_FUNCTION_SELF) != 0;
}
+ public boolean isBlockScoped() {
+ return isLet() || isConst();
+ }
+
+ public boolean hasBeenDeclared() {
+ return (flags & HAS_BEEN_DECLARED) != 0;
+ }
+
+ public void setHasBeenDeclared() {
+ if (!hasBeenDeclared()) {
+ flags |= HAS_BEEN_DECLARED;
+ }
+ }
+
/**
* Get the index of the field used to store this symbol, should it be an AccessorProperty
* and get allocated in a JO-prefixed ScriptObject subclass.
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/VarNode.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/VarNode.java Wed Jul 05 19:59:54 2017 +0200
@@ -27,6 +27,7 @@
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.parser.Token;
/**
* Node represents a var/let declaration.
@@ -43,12 +44,18 @@
private final int flags;
/** Flag that determines if this function node is a statement */
- public static final int IS_STATEMENT = 1 << 0;
+ public static final int IS_STATEMENT = 1 << 0;
+
+ /** Flag for ES6 LET declaration */
+ public static final int IS_LET = 1 << 1;
+
+ /** Flag for ES6 CONST declaration */
+ public static final int IS_CONST = 1 << 2;
/** Flag that determines if this is the last function declaration in a function
* This is used to micro optimize the placement of return value assignments for
* a program node */
- public static final int IS_LAST_FUNCTION_DECLARATION = 1 << 1;
+ public static final int IS_LAST_FUNCTION_DECLARATION = 1 << 3;
/**
* Constructor
@@ -109,6 +116,43 @@
}
/**
+ * Is this a VAR node block scoped? This returns true for ECMAScript 6 LET and CONST nodes.
+ * @return true if an ES6 LET or CONST node
+ */
+ public boolean isBlockScoped() {
+ return getFlag(IS_LET) || getFlag(IS_CONST);
+ }
+
+ /**
+ * Is this an ECMAScript 6 LET node?
+ * @return true if LET node
+ */
+ public boolean isLet() {
+ return getFlag(IS_LET);
+ }
+
+ /**
+ * Is this an ECMAScript 6 CONST node?
+ * @return true if CONST node
+ */
+ public boolean isConst() {
+ return getFlag(IS_CONST);
+ }
+
+ /**
+ * Return the flags to use for symbols for this declaration.
+ * @return the symbol flags
+ */
+ public int getSymbolFlags() {
+ if (isLet()) {
+ return Symbol.IS_VAR | Symbol.IS_LET;
+ } else if (isConst()) {
+ return Symbol.IS_VAR | Symbol.IS_CONST;
+ }
+ return Symbol.IS_VAR;
+ }
+
+ /**
* Does this variable declaration have an init value
* @return true if an init exists, false otherwise
*/
@@ -139,7 +183,7 @@
@Override
public void toString(final StringBuilder sb, final boolean printType) {
- sb.append("var ");
+ sb.append(Token.descType(getToken()).getName()).append(' ');
name.toString(sb, printType);
if (init != null) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Wed Jul 05 19:59:54 2017 +0200
@@ -45,6 +45,7 @@
import static jdk.nashorn.internal.parser.TokenType.IF;
import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX;
import static jdk.nashorn.internal.parser.TokenType.LBRACE;
+import static jdk.nashorn.internal.parser.TokenType.LET;
import static jdk.nashorn.internal.parser.TokenType.LPAREN;
import static jdk.nashorn.internal.parser.TokenType.RBRACE;
import static jdk.nashorn.internal.parser.TokenType.RBRACKET;
@@ -579,6 +580,10 @@
}
}
+ private boolean useBlockScope() {
+ return env._es6;
+ }
+
private static boolean isArguments(final String name) {
return ARGUMENTS_NAME.equals(name);
}
@@ -694,9 +699,20 @@
FunctionNode.Kind.SCRIPT,
functionLine);
+ // If ES6 block scope is enabled add a per-script block for top-level LET and CONST declarations.
+ final int startLine = start;
+ Block outer = useBlockScope() ? newBlock() : null;
functionDeclarations = new ArrayList<>();
- sourceElements(allowPropertyFunction);
- addFunctionDeclarations(script);
+
+ try {
+ sourceElements(allowPropertyFunction);
+ addFunctionDeclarations(script);
+ } finally {
+ if (outer != null) {
+ outer = restoreBlock(outer);
+ appendStatement(new BlockStatement(startLine, outer));
+ }
+ }
functionDeclarations = null;
expect(EOF);
@@ -868,7 +884,7 @@
block();
break;
case VAR:
- variableStatement(true);
+ variableStatement(type, true);
break;
case SEMICOLON:
emptyStatement();
@@ -918,8 +934,12 @@
expect(SEMICOLON);
break;
default:
+ if (useBlockScope() && (type == LET || type == CONST)) {
+ variableStatement(type, true);
+ break;
+ }
if (env._const_as_var && type == CONST) {
- variableStatement(true);
+ variableStatement(TokenType.VAR, true);
break;
}
@@ -1035,11 +1055,17 @@
* Parse a VAR statement.
* @param isStatement True if a statement (not used in a FOR.)
*/
- private List<VarNode> variableStatement(final boolean isStatement) {
+ private List<VarNode> variableStatement(final TokenType varType, final boolean isStatement) {
// VAR tested in caller.
next();
final List<VarNode> vars = new ArrayList<>();
+ int varFlags = VarNode.IS_STATEMENT;
+ if (varType == LET) {
+ varFlags |= VarNode.IS_LET;
+ } else if (varType == CONST) {
+ varFlags |= VarNode.IS_CONST;
+ }
while (true) {
// Get starting token.
@@ -1063,10 +1089,12 @@
} finally {
defaultNames.pop();
}
+ } else if (varType == CONST) {
+ throw error(AbstractParser.message("missing.const.assignment", name.getName()));
}
// Allocate var node.
- final VarNode var = new VarNode(varLine, varToken, finish, name, init);
+ final VarNode var = new VarNode(varLine, varToken, finish, name.setIsDeclaredHere(), init, varFlags);
vars.add(var);
appendStatement(var);
@@ -1180,9 +1208,12 @@
* Parse a FOR statement.
*/
private void forStatement() {
+ // When ES6 for-let is enabled we create a container block to capture the LET.
+ final int startLine = start;
+ Block outer = useBlockScope() ? newBlock() : null;
+
// Create FOR node, capturing FOR token.
ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, ForNode.IS_FOR);
-
lc.push(forNode);
try {
@@ -1203,14 +1234,19 @@
switch (type) {
case VAR:
// Var statements captured in for outer block.
- vars = variableStatement(false);
+ vars = variableStatement(type, false);
break;
case SEMICOLON:
break;
default:
+ if (useBlockScope() && (type == LET || type == CONST)) {
+ // LET/CONST captured in container block created above.
+ vars = variableStatement(type, false);
+ break;
+ }
if (env._const_as_var && type == CONST) {
// Var statements captured in for outer block.
- vars = variableStatement(false);
+ vars = variableStatement(TokenType.VAR, false);
break;
}
@@ -1290,8 +1326,13 @@
appendStatement(forNode);
} finally {
lc.pop(forNode);
+ if (outer != null) {
+ outer.setFinish(forNode.getFinish());
+ outer = restoreBlock(outer);
+ appendStatement(new BlockStatement(startLine, outer));
+ }
}
- }
+ }
/**
* ... IterationStatement :
@@ -1722,7 +1763,7 @@
}
}
- /**
+ /**
* ThrowStatement :
* throw Expression ; // [no LineTerminator here]
*
@@ -2609,7 +2650,7 @@
FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL, functionLine);
if (isStatement) {
- if (topLevel) {
+ if (topLevel || useBlockScope()) {
functionNode = functionNode.setFlag(lc, FunctionNode.IS_DECLARED);
} else if (isStrictMode) {
throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken);
@@ -2661,9 +2702,16 @@
}
if (isStatement) {
- final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, VarNode.IS_STATEMENT);
+ int varFlags = VarNode.IS_STATEMENT;
+ if (!topLevel && useBlockScope()) {
+ // mark ES6 block functions as lexically scoped
+ varFlags |= VarNode.IS_LET;
+ }
+ final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, varFlags);
if (topLevel) {
functionDeclarations.add(varNode);
+ } else if (useBlockScope()) {
+ prependStatement(varNode); // Hoist to beginning of current block
} else {
appendStatement(varNode);
}
@@ -2838,7 +2886,6 @@
}
private void addFunctionDeclarations(final FunctionNode functionNode) {
- assert lc.peek() == lc.getFunctionBody(functionNode);
VarNode lastDecl = null;
for (int i = functionDeclarations.size() - 1; i >= 0; i--) {
Statement decl = functionDeclarations.get(i);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java Wed Jul 05 19:59:54 2017 +0200
@@ -549,6 +549,8 @@
type == Object.class :
"invalid getter type " + type + " for " + getKey();
+ checkUndeclared();
+
//all this does is add a return value filter for object fields only
final MethodHandle[] getterCache = GETTER_CACHE;
final MethodHandle cachedGetter = getterCache[i];
@@ -579,6 +581,8 @@
return getOptimisticPrimitiveGetter(type, programPoint);
}
+ checkUndeclared();
+
return debug(
createGetter(
getCurrentType(),
@@ -608,6 +612,13 @@
return newMap;
}
+ private void checkUndeclared() {
+ if ((getFlags() & NEEDS_DECLARATION) != 0) {
+ // a lexically defined variable that hasn't seen its declaration - throw ReferenceError
+ throw ECMAErrors.referenceError("not.defined", getKey());
+ }
+ }
+
// the final three arguments are for debug printout purposes only
@SuppressWarnings("unused")
private static Object replaceMap(final Object sobj, final PropertyMap newMap) {
@@ -635,13 +646,14 @@
@Override
public MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap) {
- final int i = getAccessorTypeIndex(type);
- final int ci = isUndefined() ? -1 : getAccessorTypeIndex(getCurrentType());
- final Class<?> forType = isUndefined() ? type : getCurrentType();
+ checkUndeclared();
+
+ final int typeIndex = getAccessorTypeIndex(type);
+ final int currentTypeIndex = getAccessorTypeIndex(getCurrentType());
//if we are asking for an object setter, but are still a primitive type, we might try to box it
MethodHandle mh;
- if (needsInvalidator(i, ci)) {
+ if (needsInvalidator(typeIndex, currentTypeIndex)) {
final Property newProperty = getWiderProperty(type);
final PropertyMap newMap = getWiderMap(currentMap, newProperty);
@@ -652,6 +664,7 @@
mh = ObjectClassGenerator.createGuardBoxedPrimitiveSetter(ct, generateSetter(ct, ct), mh);
}
} else {
+ final Class<?> forType = isUndefined() ? type : getCurrentType();
mh = generateSetter(!forType.isPrimitive() ? Object.class : forType, type);
}
@@ -692,11 +705,12 @@
if (OBJECT_FIELDS_ONLY) {
return false;
}
- return getCurrentType() != Object.class && (isConfigurable() || isWritable());
+ // Return true for currently undefined even if non-writable/configurable to allow initialization of ES6 CONST.
+ return getCurrentType() == null || (getCurrentType() != Object.class && (isConfigurable() || isWritable()));
}
- private boolean needsInvalidator(final int ti, final int fti) {
- return canChangeType() && ti > fti;
+ private boolean needsInvalidator(final int typeIndex, final int currentTypeIndex) {
+ return canChangeType() && typeIndex > currentTypeIndex;
}
@Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Wed Jul 05 19:59:54 2017 +0200
@@ -1132,7 +1132,7 @@
if (storedScript == null) {
functionNode = new Parser(env, source, errMan, strict, getLogger(Parser.class)).parse();
- if (errors.hasErrors()) {
+ if (errMan.hasErrors()) {
return null;
}
@@ -1162,9 +1162,13 @@
env,
installer,
source,
+ errMan,
strict | functionNode.isStrict());
final FunctionNode compiledFunction = compiler.compile(functionNode, phases);
+ if (errMan.hasErrors()) {
+ return null;
+ }
script = compiledFunction.getRootClass();
compiler.persistClassInfo(cacheKey, compiledFunction);
} else {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java Wed Jul 05 19:59:54 2017 +0200
@@ -58,6 +58,18 @@
}
/**
+ * Return a copy of this FindProperty with a different property.
+ *
+ * @param newProperty the new property
+ * @return the new FindProperty instance
+ */
+ public FindProperty replaceProperty(final Property newProperty) {
+ assert this.property.getKey().equals(newProperty.getKey());
+ assert this.property.getSlot() == newProperty.getSlot();
+ return new FindProperty(self, prototype, newProperty);
+ }
+
+ /**
* Ask for a getter that returns the given type. The type has nothing to do with the
* internal representation of the property. It may be an Object (boxing primitives) or
* a primitive (primitive fields with -Dnashorn.fields.dual=true)
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java Wed Jul 05 19:59:54 2017 +0200
@@ -938,11 +938,8 @@
* @return double
*/
public static int toInt32Optimistic(final Object obj, final int programPoint) {
- if (obj != null) {
- final Class<?> clz = obj.getClass();
- if (clz == Integer.class) {
- return ((Integer)obj).intValue();
- }
+ if (obj != null && obj.getClass() == Integer.class) {
+ return ((Integer)obj).intValue();
}
throw new UnwarrantedOptimismException(obj, programPoint);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/OptimisticReturnFilters.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/OptimisticReturnFilters.java Wed Jul 05 19:59:54 2017 +0200
@@ -191,19 +191,20 @@
}
/**
- * Returns the argument value as an int. If the argument is not a Number object that can be exactly represented as
- * an int, throw an {@link UnwarrantedOptimismException}.This method is only public so that generated script code
- * can use it. See {code CodeGenerator.ENSURE_INT}.
+ * Returns the argument value as an int. If the argument is not a wrapper for a primitive numeric type
+ * with a value that can be exactly represented as an int, throw an {@link UnwarrantedOptimismException}.
+ * This method is only public so that generated script code can use it. See {code CodeGenerator.ENSURE_INT}.
* @param arg the original argument.
* @param programPoint the program point used in the exception
* @return the value of the argument as an int.
- * @throws UnwarrantedOptimismException if the argument is not a Number that can be exactly represented as an int.
+ * @throws UnwarrantedOptimismException if the argument is not a wrapper for a primitive numeric type with
+ * a value that can be exactly represented as an int.
*/
public static int ensureInt(final Object arg, final int programPoint) {
// NOTE: this doesn't delegate to ensureInt(double, int) as in that case if arg were a Long, it would throw a
// (potentially imprecise) Double in the UnwarrantedOptimismException. This way, it will put the correct valued
// Long into the exception.
- if (arg instanceof Number) {
+ if (isPrimitiveNumberWrapper(arg)) {
final double d = ((Number)arg).doubleValue();
if (JSType.isRepresentableAsInt(d) && !JSType.isNegativeZero(d)) {
return (int)d;
@@ -212,6 +213,15 @@
throw new UnwarrantedOptimismException(arg, programPoint);
}
+ private static boolean isPrimitiveNumberWrapper(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ final Class<?> c = obj.getClass();
+ return c == Integer.class || c == Double.class || c == Long.class ||
+ c == Float.class || c == Short.class || c == Byte.class;
+ }
+
@SuppressWarnings("unused")
private static int ensureInt(final boolean arg, final int programPoint) {
throw new UnwarrantedOptimismException(arg, programPoint, Type.OBJECT);
@@ -236,35 +246,40 @@
}
/**
- * Returns the argument value as a long. If the argument is not a Number object that can be exactly represented as
- * a long, throw an {@link UnwarrantedOptimismException}.This method is only public so that generated script code
- * can use it. See {code CodeGenerator.ENSURE_LONG}.
+ * Returns the argument value as a long. If the argument is not a wrapper for a primitive numeric type
+ * with a value that can be exactly represented as a long, throw an {@link UnwarrantedOptimismException}.
+ * This method is only public so that generated script code can use it. See {code CodeGenerator.ENSURE_LONG}.
* @param arg the original argument.
* @param programPoint the program point used in the exception
* @return the value of the argument as a long.
- * @throws UnwarrantedOptimismException if the argument is not a Number that can be exactly represented as a long.
+ * @throws UnwarrantedOptimismException if the argument is not a wrapper for a primitive numeric type with
+ * a value that can be exactly represented as a long
*/
public static long ensureLong(final Object arg, final int programPoint) {
- if (arg instanceof Long) {
- // Must check for Long separately, as Long.doubleValue() isn't precise.
- return ((Long)arg).longValue();
- } else if (arg instanceof Number) {
- return ensureLong(((Number)arg).doubleValue(), programPoint);
+ if (arg != null) {
+ final Class<?> c = arg.getClass();
+ if (c == Long.class) {
+ // Must check for Long separately, as Long.doubleValue() isn't precise.
+ return ((Long)arg).longValue();
+ } else if (c == Integer.class || c == Double.class || c == Float.class || c == Short.class ||
+ c == Byte.class) {
+ return ensureLong(((Number)arg).doubleValue(), programPoint);
+ }
}
throw new UnwarrantedOptimismException(arg, programPoint);
}
/**
- * Returns the argument value as a double. If the argument is not a Number object, throw an
- * {@link UnwarrantedOptimismException}.This method is only public so that generated script code can use it. See
- * {code CodeGenerator.ENSURE_NUMBER}.
+ * Returns the argument value as a double. If the argument is not a a wrapper for a primitive numeric type
+ * throw an {@link UnwarrantedOptimismException}.This method is only public so that generated script code
+ * can use it. See {code CodeGenerator.ENSURE_NUMBER}.
* @param arg the original argument.
* @param programPoint the program point used in the exception
* @return the value of the argument as a double.
- * @throws UnwarrantedOptimismException if the argument is not a Number that can be exactly represented as a long.
+ * @throws UnwarrantedOptimismException if the argument is not a wrapper for a primitive numeric type.
*/
public static double ensureNumber(final Object arg, final int programPoint) {
- if (arg instanceof Number) { // arg == null -> false
+ if (isPrimitiveNumberWrapper(arg)) {
return ((Number)arg).doubleValue();
}
throw new UnwarrantedOptimismException(arg, programPoint);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java Wed Jul 05 19:59:54 2017 +0200
@@ -82,11 +82,14 @@
* is narrower than object, e.g. Math.PI which is declared
* as a double
*/
- public static final int IS_NASGEN_PRIMITIVE = 1 << 6;
+ public static final int IS_NASGEN_PRIMITIVE = 1 << 6;
/** Is this property bound to a receiver? This means get/set operations will be delegated to
* a statically defined object instead of the object passed as callsite parameter. */
- public static final int IS_BOUND = 1 << 8;
+ public static final int IS_BOUND = 1 << 7;
+
+ /** Is this a lexically scoped LET or CONST variable that is dead until it is declared. */
+ public static final int NEEDS_DECLARATION = 1 << 8;
/** Property key. */
private final String key;
@@ -287,6 +290,15 @@
}
/**
+ * Is this a LET or CONST property that needs to see its declaration before being usable?
+ *
+ * @return true if this is a block-scoped variable
+ */
+ public boolean needsDeclaration() {
+ return (flags & NEEDS_DECLARATION) == NEEDS_DECLARATION;
+ }
+
+ /**
* Add more property flags to the property. Properties are immutable here,
* so any property change that results in a larger flag set results in the
* property being cloned. Use only the return value
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Wed Jul 05 19:59:54 2017 +0200
@@ -394,6 +394,7 @@
context.getEnv(),
installer,
functionNode.getSource(), // source
+ context.getErrorManager(),
isStrict() | functionNode.isStrict(), // is strict
true, // is on demand
this, // compiledFunction, i.e. this RecompilableScriptFunctionData
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java Wed Jul 05 19:59:54 2017 +0200
@@ -94,6 +94,9 @@
/** Use single Global instance per jsr223 engine instance. */
public final boolean _global_per_engine;
+ /** Enable experimental ECMAScript 6 features. */
+ public final boolean _es6;
+
/** Argument passed to compile only if optimistic compilation should take place */
public static final String COMPILE_ONLY_OPTIMISTIC_ARG = "optimistic";
@@ -258,6 +261,15 @@
_version = options.getBoolean("version");
_verify_code = options.getBoolean("verify.code");
+ final String language = options.getString("language");
+ if (language == null || language.equals("es5")) {
+ _es6 = false;
+ } else if (language.equals("es6")) {
+ _es6 = true;
+ } else {
+ throw new RuntimeException("Unsupported language: " + language);
+ }
+
String dir = null;
String func = null;
final String pc = options.getString("print.code");
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java Wed Jul 05 19:59:54 2017 +0200
@@ -36,6 +36,7 @@
import java.lang.invoke.MethodType;
import java.lang.invoke.SwitchPoint;
import java.util.Collections;
+
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
@@ -44,6 +45,9 @@
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.objects.NativeFunction;
+import jdk.nashorn.internal.runtime.ScriptFunctionData;
+import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
@@ -621,6 +625,23 @@
appliedType = appliedType.changeParameterType(1, Object.class);
}
+ /*
+ * dropArgs is a synthetic method handle that contains any args that we need to
+ * get rid of that come after the arguments array in the apply case. We adapt
+ * the callsite to ask for 3 args only and then dropArguments on the method handle
+ * to make it fit the extraneous args.
+ */
+ MethodType dropArgs = MH.type(void.class);
+ if (isApply && !isFailedApplyToCall) {
+ final int pc = appliedType.parameterCount();
+ for (int i = 3; i < pc; i++) {
+ dropArgs = dropArgs.appendParameterTypes(appliedType.parameterType(i));
+ }
+ if (pc > 3) {
+ appliedType = appliedType.dropParameterTypes(3, pc);
+ }
+ }
+
if (isApply || isFailedApplyToCall) {
if (passesArgs) {
// R(this, args) => R(this, Object[])
@@ -702,6 +723,15 @@
}
inv = MH.dropArguments(inv, 0, applyFnType);
+ /*
+ * Dropargs can only be non-()V in the case of isApply && !isFailedApplyToCall, which
+ * is when we need to add arguments to the callsite to catch and ignore the synthetic
+ * extra args that someone has added to the command line.
+ */
+ for (int i = 0; i < dropArgs.parameterCount(); i++) {
+ inv = MH.dropArguments(inv, 4 + i, dropArgs.parameterType(i));
+ }
+
MethodHandle guard = appliedInvocation.getGuard();
// If the guard checks the value of "this" but we aren't passing thisArg, insert the default one
if (!passesThis && guard.type().parameterCount() > 1) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Wed Jul 05 19:59:54 2017 +0200
@@ -158,6 +158,7 @@
static final MethodHandle MEGAMORPHIC_GET = findOwnMH_V("megamorphicGet", Object.class, String.class, boolean.class);
static final MethodHandle GLOBALFILTER = findOwnMH_S("globalFilter", Object.class, Object.class);
+ static final MethodHandle DECLARE_AND_SET = findOwnMH_V("declareAndSet", void.class, String.class, Object.class);
private static final MethodHandle TRUNCATINGFILTER = findOwnMH_S("truncatingFilter", Object[].class, int.class, Object[].class);
private static final MethodHandle KNOWNFUNCPROPGUARDSELF = findOwnMH_S("knownFunctionPropertyGuardSelf", boolean.class, Object.class, PropertyMap.class, MethodHandle.class, ScriptFunction.class);
@@ -2027,6 +2028,22 @@
return isMethod ? getNoSuchMethod(key, INVALID_PROGRAM_POINT) : invokeNoSuchProperty(key, INVALID_PROGRAM_POINT);
}
+ // Marks a property as declared and sets its value. Used as slow path for block-scoped LET and CONST
+ @SuppressWarnings("unused")
+ private void declareAndSet(final String key, final Object value) {
+ final PropertyMap map = getMap();
+ final FindProperty find = findProperty(key, false);
+ assert find != null;
+
+ final Property property = find.getProperty();
+ assert property != null;
+ assert property.needsDeclaration();
+
+ final PropertyMap newMap = map.replaceProperty(property, property.removeFlags(Property.NEEDS_DECLARATION));
+ setMap(newMap);
+ set(key, value, true);
+ }
+
/**
* Find the appropriate GETINDEX method for an invoke dynamic call.
*
@@ -2140,7 +2157,7 @@
}
if (find != null) {
- if (!find.getProperty().isWritable()) {
+ if (!find.getProperty().isWritable() && !NashornCallSiteDescriptor.isDeclaration(desc)) {
// Existing, non-writable property
return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java Wed Jul 05 19:59:54 2017 +0200
@@ -108,6 +108,11 @@
public static final Call APPLY = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "apply", Object.class, ScriptFunction.class, Object.class, Object[].class);
/**
+ * Throws a reference error for an undefined variable.
+ */
+ public static final Call THROW_REFERENCE_ERROR = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "throwReferenceError", void.class, String.class);
+
+ /**
* Converts a switch tag value to a simple integer. deflt value if it can't.
*
* @param tag Switch statement tag value.
@@ -382,6 +387,15 @@
}
/**
+ * Throws a reference error for an undefined variable.
+ *
+ * @param name the variable name
+ */
+ public static void throwReferenceError(final String name) {
+ throw referenceError("not.defined", name);
+ }
+
+ /**
* Call a script function as a constructor with given args.
*
* @param target ScriptFunction object.
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java Wed Jul 05 19:59:54 2017 +0200
@@ -140,7 +140,29 @@
private SetMethod createExistingPropertySetter() {
final Property property = find.getProperty();
- final MethodHandle methodHandle = find.getSetter(type, NashornCallSiteDescriptor.isStrict(desc));
+ final MethodHandle methodHandle;
+
+ if (NashornCallSiteDescriptor.isDeclaration(desc)) {
+ assert property.needsDeclaration();
+ // This is a LET or CONST being declared. The property is already there but flagged as needing declaration.
+ // We create a new PropertyMap with the flag removed. The map is installed with a fast compare-and-set
+ // method if the pre-callsite map is stable (which should be the case for function scopes except for
+ // non-strict functions containing eval() with var). Otherwise we have to use a slow setter that creates
+ // a new PropertyMap on the fly.
+ final PropertyMap oldMap = getMap();
+ final Property newProperty = property.removeFlags(Property.NEEDS_DECLARATION);
+ final PropertyMap newMap = oldMap.replaceProperty(property, newProperty);
+ final MethodHandle fastSetter = find.replaceProperty(newProperty).getSetter(type, NashornCallSiteDescriptor.isStrict(desc));
+ final MethodHandle slowSetter = MH.insertArguments(ScriptObject.DECLARE_AND_SET, 1, getName()).asType(fastSetter.type());
+
+ // cas map used as guard, if true that means we can do the set fast
+ MethodHandle casMap = MH.insertArguments(ScriptObject.CAS_MAP, 1, oldMap, newMap);
+ casMap = MH.dropArguments(casMap, 1, type);
+ casMap = MH.asType(casMap, casMap.type().changeParameterType(0, Object.class));
+ methodHandle = MH.guardWithTest(casMap, fastSetter, slowSetter);
+ } else {
+ methodHandle = find.getSetter(type, NashornCallSiteDescriptor.isStrict(desc));
+ }
assert methodHandle != null;
assert property != null;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java Wed Jul 05 19:59:54 2017 +0200
@@ -628,18 +628,20 @@
Class<?> widest = Integer.class;
for (final Object item : items) {
- final Class<?> itemClass = item == null ? null : item.getClass();
+ if (item == null) {
+ return Object.class;
+ }
+ final Class<?> itemClass = item.getClass();
if (itemClass == Long.class) {
if (widest == Integer.class) {
widest = Long.class;
}
- } else if (itemClass == Double.class) {
+ } else if (itemClass == Double.class || itemClass == Float.class) {
if (widest == Integer.class || widest == Long.class) {
widest = Double.class;
}
- } else if (!(item instanceof Number)) {
- widest = Object.class;
- break;
+ } else if (itemClass != Integer.class && itemClass != Short.class && itemClass != Byte.class) {
+ return Object.class;
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java Wed Jul 05 19:59:54 2017 +0200
@@ -54,23 +54,25 @@
public static final int CALLSITE_OPTIMISTIC = 1 << 3;
/** Is this really an apply that we try to call as a call? */
public static final int CALLSITE_APPLY_TO_CALL = 1 << 4;
+ /** Does this a callsite for a variable declaration? */
+ public static final int CALLSITE_DECLARE = 1 << 5;
/** Flags that the call site is profiled; Contexts that have {@code "profile.callsites"} boolean property set emit
* code where call sites have this flag set. */
- public static final int CALLSITE_PROFILE = 1 << 5;
+ public static final int CALLSITE_PROFILE = 1 << 6;
/** Flags that the call site is traced; Contexts that have {@code "trace.callsites"} property set emit code where
* call sites have this flag set. */
- public static final int CALLSITE_TRACE = 1 << 6;
+ public static final int CALLSITE_TRACE = 1 << 7;
/** Flags that the call site linkage miss (and thus, relinking) is traced; Contexts that have the keyword
* {@code "miss"} in their {@code "trace.callsites"} property emit code where call sites have this flag set. */
- public static final int CALLSITE_TRACE_MISSES = 1 << 7;
+ public static final int CALLSITE_TRACE_MISSES = 1 << 8;
/** Flags that entry/exit to/from the method linked at call site are traced; Contexts that have the keyword
* {@code "enterexit"} in their {@code "trace.callsites"} property emit code where call sites have this flag set. */
- public static final int CALLSITE_TRACE_ENTEREXIT = 1 << 8;
+ public static final int CALLSITE_TRACE_ENTEREXIT = 1 << 9;
/** Flags that values passed as arguments to and returned from the method linked at call site are traced; Contexts
* that have the keyword {@code "values"} in their {@code "trace.callsites"} property emit code where call sites
* have this flag set. */
- public static final int CALLSITE_TRACE_VALUES = 1 << 9;
+ public static final int CALLSITE_TRACE_VALUES = 1 << 10;
//we could have more tracing flags here, for example CALLSITE_TRACE_SCOPE, but bits are a bit precious
//right now given the program points
@@ -82,10 +84,10 @@
* TODO: rethink if we need the various profile/trace flags or the linker can use the Context instead to query its
* trace/profile settings.
*/
- public static final int CALLSITE_PROGRAM_POINT_SHIFT = 10;
+ public static final int CALLSITE_PROGRAM_POINT_SHIFT = 11;
/**
- * Maximum program point value. 22 bits should be enough for anyone
+ * Maximum program point value. 21 bits should be enough for anyone
*/
public static final int MAX_PROGRAM_POINT_VALUE = (1 << 32 - CALLSITE_PROGRAM_POINT_SHIFT) - 1;
@@ -123,6 +125,9 @@
assert (flags & CALLSITE_FAST_SCOPE) == 0 : "can't be fastscope without scope";
sb.append("scope ");
}
+ if ((flags & CALLSITE_DECLARE) != 0) {
+ sb.append("declare ");
+ }
}
if ((flags & CALLSITE_APPLY_TO_CALL) != 0) {
sb.append("apply2call ");
@@ -329,6 +334,15 @@
}
/**
+ * Does this callsite contain a declaration for its target?
+ * @param desc descriptor
+ * @return true if contains declaration
+ */
+ public static boolean isDeclaration(final CallSiteDescriptor desc) {
+ return isFlag(desc, CALLSITE_DECLARE);
+ }
+
+ /**
* Get a program point from a descriptor (must be optimistic)
* @param desc descriptor
* @return program point
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties Wed Jul 05 19:59:54 2017 +0200
@@ -58,6 +58,7 @@
parser.error.regex.repeated.flag=Repeated RegExp flag: {0}
parser.error.regex.syntax={0}
parser.error.trailing.comma.in.json=Trailing comma is not allowed in JSON
+parser.error.missing.const.assignment=Missing assignment to constant "{0}"
# strict mode error messages
parser.error.strict.no.with="with" statement cannot be used in strict mode
@@ -162,6 +163,8 @@
syntax.error.invalid.json=Invalid JSON: {0}
syntax.error.strict.cant.delete=cannot delete "{0}" in strict mode
+syntax.error.redeclare.variable=Variable "{0}" has already been declared
+syntax.error.assign.constant=Assignment to constant "{0}"
io.error.cant.write=cannot write "{0}"
config.error.no.dest=no destination directory supplied
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Options.properties Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Options.properties Wed Jul 05 19:59:54 2017 +0200
@@ -329,6 +329,14 @@
desc="Enable scripting features." \
}
+nashorn.option.language = { \
+ name="--language", \
+ type=String, \
+ params=[es5|es6], \
+ default=es5, \
+ desc="Specify ECMAScript language version." \
+}
+
nashorn.option.stdout = { \
name="--stdout", \
is_undocumented=true, \
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java Wed Jul 05 19:59:54 2017 +0200
@@ -252,6 +252,15 @@
return COMPILATION_ERROR;
}
+ new Compiler(
+ context,
+ env,
+ null, //null - pass no code installer - this is compile only
+ functionNode.getSource(),
+ context.getErrorManager(),
+ env._strict | functionNode.isStrict()).
+ compile(functionNode, CompilationPhases.COMPILE_ALL_NO_INSTALL);
+
if (env._print_ast) {
context.getErr().println(new ASTWriter(functionNode));
}
@@ -260,14 +269,9 @@
context.getErr().println(new PrintVisitor(functionNode));
}
- //null - pass no code installer - this is compile only
- new Compiler(
- context,
- env,
- null,
- functionNode.getSource(),
- env._strict | functionNode.isStrict()).
- compile(functionNode, CompilationPhases.COMPILE_ALL_NO_INSTALL);
+ if (errors.getNumberOfErrors() != 0) {
+ return COMPILATION_ERROR;
+ }
}
} finally {
env.getOut().flush();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8056129.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * JDK-8056129: AtomicInteger is treated as primitive number with optimistic compilation
+ *
+ * @test
+ * @run
+ */
+
+var AtomicInteger = java.util.concurrent.atomic.AtomicInteger;
+
+function getAtomic() {
+ return new AtomicInteger()
+}
+var x = getAtomic()
+print(x instanceof AtomicInteger)
+
+var a = []
+a.push(x)
+var y = a[0]
+print(y instanceof AtomicInteger)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8056129.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,2 @@
+true
+true
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8057019-2.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * this apply with extra arguments
+ * (with apply to call enabled)
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + 'JDK-8057019-payload.js');
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8057019-2.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,24 @@
+1 2 undefined
+1 2 3
+1 2 3
+1 2 undefined
+1 2 3
+1 2 3
+1 2 undefined
+1 2 3
+1 2 3
+1 2 undefined
+1 2 3
+1 2 3
+1 2 undefined
+1 2 3
+1 2 3
+23 apa gorilla
+23 apa gorilla
+23 apa gorilla
+23 apa gorilla
+23 apa gorilla
+23 apa gorilla
+TypeError: Function.prototype.apply expects an Array for second argument
+TypeError: Function.prototype.apply expects an Array for second argument
+TypeError: Function.prototype.apply expects an Array for second argument
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8057019-payload.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * this apply with extra arguments
+ *
+ * @subtest
+ */
+
+function func(x, y, z) {
+ print(x, y, z);
+}
+
+function g() {
+ func.apply(this, arguments);
+}
+function h() {
+ func.apply(this, arguments, 23);
+}
+function i() {
+ func.apply(this, arguments, 23, 4711);
+}
+function j() {
+ func.apply(this, arguments, 23, 4711, "apa", "dingo", "gorilla");
+}
+function k() {
+ func.apply(this, arguments, 23);
+}
+function l() {
+ func.apply(this, [23, "apa", "gorilla", "dingo"], 17);
+}
+function m() {
+ func.apply(this, [23, "apa", "gorilla", "dingo"]);
+}
+function n() {
+ func.apply(this, "significant");
+}
+
+g(1,2);
+g(1,2,3);
+g(1,2,3,4);
+
+h(1,2);
+h(1,2,3);
+h(1,2,3,4);
+
+i(1,2);
+i(1,2,3);
+i(1,2,3,4);
+
+j(1,2);
+j(1,2,3);
+j(1,2,3,4);
+
+k(1,2);
+k(1,2,3);
+k(1,2,3,4);
+
+l(1,2);
+l(1,2,3);
+l(1,2,3,4);
+
+m(1,2);
+m(1,2,3);
+m(1,2,3,4);
+
+try {
+ n(1,2);
+} catch (e) {
+ print(e);
+}
+try {
+ n(1,2,3);
+} catch (e) {
+ print(e);
+}
+
+try {
+ n(1,2,3,4);
+} catch (e) {
+ print(e);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8057019.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * this apply with extra arguments
+ * (turning off apply to call)
+ *
+ * @fork
+ * @option -Dnashorn.apply2call=false
+ * @test
+ * @run
+ */
+
+load(__DIR__ + 'JDK-8057019-payload.js');
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8057019.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,24 @@
+1 2 undefined
+1 2 3
+1 2 3
+1 2 undefined
+1 2 3
+1 2 3
+1 2 undefined
+1 2 3
+1 2 3
+1 2 undefined
+1 2 3
+1 2 3
+1 2 undefined
+1 2 3
+1 2 3
+23 apa gorilla
+23 apa gorilla
+23 apa gorilla
+23 apa gorilla
+23 apa gorilla
+23 apa gorilla
+TypeError: Function.prototype.apply expects an Array for second argument
+TypeError: Function.prototype.apply expects an Array for second argument
+TypeError: Function.prototype.apply expects an Array for second argument
--- a/nashorn/test/script/basic/apply_to_call/apply_to_call4.js.EXPECTED Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/test/script/basic/apply_to_call/apply_to_call4.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -15,8 +15,8 @@
2.3
3.4
test 5 done
-a=object
-17
+a=number
+22
undefined
Now it's time for transforms
19
--- a/nashorn/test/script/basic/compile-octane-normal.js Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/test/script/basic/compile-octane-normal.js Wed Jul 05 19:59:54 2017 +0200
@@ -38,5 +38,5 @@
*/
var fn = __DIR__ + 'compile-octane.js';
-var url = "file://" + fn;
-loadWithNewGlobal(new java.net.URL(url));
+var url = new java.io.File(fn).toURL();
+loadWithNewGlobal(url);
--- a/nashorn/test/script/basic/compile-octane-splitter.js Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/test/script/basic/compile-octane-splitter.js Wed Jul 05 19:59:54 2017 +0200
@@ -40,5 +40,5 @@
*/
var fn = __DIR__ + 'compile-octane.js';
-var url = "file://" + fn;
-loadWithNewGlobal(new java.net.URL(url));
+var url = new java.io.File(fn).toURL();
+loadWithNewGlobal(url);
--- a/nashorn/test/script/basic/compile-octane.js Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/test/script/basic/compile-octane.js Wed Jul 05 19:59:54 2017 +0200
@@ -132,7 +132,7 @@
str2 += " processing file: " + file + "...";
print_if_verbose(str2);
}
- newGlobal.load("file://" + path + file);
+ newGlobal.load(new java.io.File(path + file).toURL());
}
}
print("Done.");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/block-function-decl.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+"use strict";
+
+{
+ // f is defined on block level
+ print(f);
+ f();
+ function f() {
+ print("in f");
+ }
+ print(f);
+ f();
+}
+
+try {
+ print(typeof f);
+ f();
+} catch (e) {
+ print(e);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/block-function-decl.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,10 @@
+function f() {
+ print("in f");
+ }
+in f
+function f() {
+ print("in f");
+ }
+in f
+undefined
+ReferenceError: "f" is not defined
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-empty.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+try {
+ eval('"use strict";\n' +
+ 'const x;\n');
+} catch (e) {
+ print(e);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-empty.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,3 @@
+SyntaxError: test/script/basic/es6/const-empty.js#33:4<eval>@1:2:7 Missing assignment to constant "x"
+const x;
+ ^
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-reassign.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+try {
+ eval('"use strict";\n' +
+ 'const x = 2;\n' +
+ 'x = 1;\n');
+} catch (e) {
+ print(e.name);
+}
+
+try {
+ eval('"use strict";\n' +
+ 'const x = 2;\n' +
+ 'x++;\n');
+ fail("const assignment didn't throw");
+} catch (e) {
+ print(e.name);
+}
+
+try {
+ eval('"use strict";\n' +
+ 'const x = 2;\n' +
+ 'x--;\n');
+ fail("const assignment didn't throw");
+} catch (e) {
+ print(e.name);
+}
+
+try {
+ eval('"use strict";\n' +
+ 'const x = 2;\n' +
+ '++x;\n');
+ fail("const assignment didn't throw");
+} catch (e) {
+ print(e.name);
+}
+
+try {
+ eval('"use strict";\n' +
+ 'const x = 2;\n' +
+ '--x;\n');
+ fail("const assignment didn't throw");
+} catch (e) {
+ print(e.name);
+}
+
+try {
+ eval('"use strict";\n' +
+ 'const x = 2;\n' +
+ 'x += 1;\n');
+ fail("const assignment didn't throw");
+} catch (e) {
+ print(e.name);
+}
+
+try {
+ eval('"use strict";\n' +
+ 'const x = 2;\n' +
+ 'x *= 1;\n');
+ fail("const assignment didn't throw");
+} catch (e) {
+ print(e.name);
+}
+
+try {
+ eval('"use strict";\n' +
+ 'const x = 2;\n' +
+ 'x /= 1;\n');
+ fail("const assignment didn't throw");
+} catch (e) {
+ print(e.name);
+}
+
+try {
+ eval('"use strict";\n' +
+ 'const x = 2;\n' +
+ 'x %= 1;\n');
+ fail("const assignment didn't throw");
+} catch (e) {
+ print(e.name);
+}
+
+try {
+ eval('"use strict";\n' +
+ 'const x = 2;\n' +
+ 'x |= 1;\n');
+ fail("const assignment didn't throw");
+} catch (e) {
+ print(e.name);
+}
+
+try {
+ eval('"use strict";\n' +
+ 'const x = 2;\n' +
+ 'x &= 1;\n');
+ fail("const assignment didn't throw");
+} catch (e) {
+ print(e.name);
+}
+
+try {
+ eval('"use strict";\n' +
+ 'const x = 2;\n' +
+ 'x ^= 1;\n');
+ fail("const assignment didn't throw");
+} catch (e) {
+ print(e.name);
+}
+
+try {
+ eval('"use strict";\n' +
+ 'const x = 2;\n' +
+ 'x <<= 1;\n');
+ fail("const assignment didn't throw");
+} catch (e) {
+ print(e.name);
+}
+
+try {
+ eval('"use strict";\n' +
+ 'const x = 2;\n' +
+ 'x >>= 1;\n');
+ fail("const assignment didn't throw");
+} catch (e) {
+ print(e.name);
+}
+
+try {
+ eval('"use strict";\n' +
+ 'const x = 2;\n' +
+ 'x >>>= 1;\n');
+ fail("const assignment didn't throw");
+} catch (e) {
+ print(e.name);
+}
+
+try {
+ eval('"use strict";\n' +
+ 'const x = 2;\n' +
+ 'delete x;\n');
+ fail("const assignment didn't throw");
+} catch (e) {
+ print(e.name);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-reassign.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,16 @@
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-redeclare.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+try {
+ eval('"use strict";\n' +
+ 'const x = 2;\n' +
+ 'const x = 2;\n');
+} catch (e) {
+ print(e);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-redeclare.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,3 @@
+SyntaxError: test/script/basic/es6/const-redeclare.js#33:4<eval>@1:2:6 Variable "x" has already been declared
+const x = 2;
+ ^
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-self.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+const a = 1, b = a;
+
+print(a, b);
+
+try {
+ eval('"use strict";\n' +
+ 'const a = a;\n');
+} catch (e) {
+ print(e);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-self.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,2 @@
+1 1
+ReferenceError: "a" is not defined
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-tdz.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+{
+ print("test 1");
+
+ function f() {
+ try {
+ print(a);
+ } catch (a) {
+ print(a);
+ }
+ }
+
+ f();
+ const a = 1;
+ f();
+}
+
+{
+ print("test 2");
+
+ function f() {
+ try {
+ print(a);
+ } catch (a) {
+ print(a);
+ }
+ }
+
+ f();
+ const a = 2;
+ f();
+}
+
+{
+ print("test 3");
+ {
+ try {
+ print(a);
+ } catch (a) {
+ print(a);
+ }
+ }
+
+ const a = 3;
+
+ {
+ print(a);
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-tdz.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,9 @@
+test 1
+ReferenceError: "a" is not defined
+1
+test 2
+ReferenceError: "a" is not defined
+2
+test 3
+ReferenceError: "a" is not defined
+3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+"use strict";
+
+const a = 2;
+const c = 2;
+print(a, c);
+
+function f(x) {
+ const a = 5;
+ const c = 10;
+ print(a, c);
+ if (x) {
+ const a = 42;
+ const c = 43;
+ print(a, c);
+ }
+ print(a, c);
+
+ function inner() {
+ (function() {
+ print(a, c);
+ })();
+ }
+ inner();
+}
+
+f(true);
+f(false);
+
+(function() {
+ (function() {
+ print(a, c);
+ })();
+})();
+
+function outer() {
+ print(a, c);
+}
+outer();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,10 @@
+2 2
+5 10
+42 43
+5 10
+5 10
+5 10
+5 10
+5 10
+2 2
+2 2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/for-let.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+for (let i = 0; i < 10; i++) {
+ print(i);
+}
+
+try {
+ print(i);
+} catch (e) {
+ print(e);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/for-let.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,11 @@
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+ReferenceError: "i" is not defined
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-eval.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+function f() {
+ var a;
+ let b;
+ const c = 0;
+
+ print(a, b, c);
+
+ try {
+ eval("x = 1; print('x: ' + x);");
+ print("assignment to x succeeded");
+ } catch (e) {
+ print(e);
+ }
+ try {
+ eval("'use strict'; let z = 1; print('z: ' + z);");
+ print("assignment to z succeeded");
+ eval("print('z: ' + z);");
+ } catch (e) {
+ print(e);
+ }
+
+ try {
+ eval("a = 1; print(a);");
+ print("assignment to a succeeded");
+ } catch (e) {
+ print(e);
+ }
+ print("a: " + a);
+
+ try {
+ eval("b = 1; print('b: ' + b);");
+ print("assignment to b succeeded");
+ } catch (e) {
+ print(e);
+ }
+ print("b: " + b);
+
+ try {
+ eval("c = 1; print('c: ' + c);");
+ print("assignment to c succeeded");
+ } catch (e) {
+ print(e);
+ }
+ print("c: " + c);
+
+ eval("a = 2; let b = 3;");
+
+ try {
+ print(a, b, c);
+ } catch (e) {
+ print(e);
+ }
+
+ let x;
+
+ try {
+ print(a, b, c, x);
+ } catch (e) {
+ print(e);
+ }
+
+}
+
+f();
+
+print(typeof a, typeof b, typeof c, typeof x, typeof z);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-eval.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,16 @@
+undefined undefined 0
+ReferenceError: "x" is not defined
+z: 1
+assignment to z succeeded
+ReferenceError: "z" is not defined
+1
+assignment to a succeeded
+a: 1
+b: 1
+assignment to b succeeded
+b: 1
+TypeError: "c" is not a writable property of [object Object]
+c: 0
+2 1 0
+2 1 0 undefined
+undefined undefined undefined undefined undefined
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-load-lib.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * @subtest
+ */
+
+"use strict";
+
+// var should be visible in other script, let and const not
+var a = 1;
+let b = 2;
+const c = 3;
+
+// top level function should be visible
+function top() {
+ print("top level function");
+}
+
+// block level function not visible outside script
+{
+ function block() {
+ print("block function");
+ }
+
+ top();
+ block();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-load.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+load(__DIR__ + "let-load-lib.js");
+
+{
+ let a = 20;
+ const c = 30;
+ print("print local defs: " + a, c);
+}
+
+print("imported var: " + a);
+try {
+ print("imported let: " + b);
+} catch (e) {
+ print(e);
+}
+
+try {
+ print("imported const: " + c);
+} catch (e) {
+ print(e);
+}
+
+top();
+
+try {
+ block();
+} catch (e) {
+ print(e);
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-load.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,8 @@
+top level function
+block function
+print local defs: 20 30
+imported var: 1
+ReferenceError: "b" is not defined
+ReferenceError: "c" is not defined
+top level function
+ReferenceError: "block" is not defined
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-nodeclare.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+try {
+ if (true) {
+ let x = 2;
+ print(x);
+ }
+ print(x);
+} catch (e) {
+ print(e);
+}
+
+
+try {
+ if (true) {
+ const x = 2;
+ print(x);
+ }
+ print(x);
+} catch (e) {
+ print(e);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-nodeclare.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,4 @@
+2
+ReferenceError: "x" is not defined
+2
+ReferenceError: "x" is not defined
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-redeclare.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+try {
+ eval('"use strict";\n' +
+ 'let x = 2;\n' +
+ 'let x = 2;\n');
+} catch (e) {
+ print(e);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-redeclare.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,3 @@
+SyntaxError: test/script/basic/es6/let-redeclare.js#33:4<eval>@1:2:4 Variable "x" has already been declared
+let x = 2;
+ ^
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-self.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+let a, b = a;
+
+print(a, b);
+
+try {
+ eval('"use strict";\n' +
+ 'let a = a;\n');
+} catch (e) {
+ print(e);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-self.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,2 @@
+undefined undefined
+ReferenceError: "a" is not defined
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-tdz.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+{
+ print("test 1");
+
+ function f() {
+ try {
+ print(a);
+ } catch (a) {
+ print(a);
+ }
+ }
+
+ f();
+ let a = 1;
+ f();
+}
+
+{
+ print("test 2");
+
+ function f() {
+ try {
+ print(a);
+ } catch (a) {
+ print(a);
+ }
+ }
+
+ f();
+ let a = 2;
+ f();
+}
+
+{
+ print("test 3");
+
+ {
+ try {
+ print(a);
+ } catch (a) {
+ print(a);
+ }
+ }
+
+ let a = 3;
+
+ {
+ print(a);
+ }
+}
+
+{
+ print("test 4");
+ let a;
+
+ {
+ print(a);
+ }
+
+ a = 4;
+
+ {
+ print(a);
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-tdz.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,12 @@
+test 1
+ReferenceError: "a" is not defined
+1
+test 2
+ReferenceError: "a" is not defined
+2
+test 3
+ReferenceError: "a" is not defined
+3
+test 4
+undefined
+4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let.js Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+let a = 2;
+let c = 2;
+print(a, c);
+
+function f(x) {
+ let a = 5;
+ const c = 10;
+ print(a, c);
+ if (x) {
+ let a = 42;
+ const c = 43;
+ print(a, c);
+ }
+ print(a, c);
+
+ function inner() {
+ (function() {
+ print(a, c);
+ })();
+ }
+ inner();
+}
+
+f(true);
+f(false);
+
+(function() {
+ (function() {
+ print(a, c);
+ })();
+})();
+
+function outer() {
+ print(a, c);
+}
+outer();
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let.js.EXPECTED Wed Jul 05 19:59:54 2017 +0200
@@ -0,0 +1,10 @@
+2 2
+5 10
+42 43
+5 10
+5 10
+5 10
+5 10
+5 10
+2 2
+2 2
--- a/nashorn/test/script/trusted/JDK-8006529.js Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/test/script/trusted/JDK-8006529.js Wed Jul 05 19:59:54 2017 +0200
@@ -120,7 +120,7 @@
var sourceForMethod = Source.class.getMethod("sourceFor", java.lang.String.class, java.lang.String.class)
var ParserConstructor = Parser.class.getConstructor(ScriptEnvironment.class, Source.class, ErrorManager.class)
-var CompilerConstructor = Compiler.class.getConstructor(Context.class, ScriptEnvironment.class, CodeInstaller.class, Source.class, boolean.class);
+var CompilerConstructor = Compiler.class.getConstructor(Context.class, ScriptEnvironment.class, CodeInstaller.class, Source.class, ErrorManager.class, boolean.class);
// compile(script) -- compiles a script specified as a string with its
// source code, returns a jdk.nashorn.internal.ir.FunctionNode object
@@ -134,7 +134,7 @@
var parser = ParserConstructor.newInstance(env, source, ThrowErrorManager.class.newInstance());
var func = parseMethod.invoke(parser);
- var compiler = CompilerConstructor.newInstance(ctxt, env, null, source, false);
+ var compiler = CompilerConstructor.newInstance(ctxt, env, null, source, null, false);
return compileMethod.invoke(compiler, func, phases);
};
--- a/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -98,11 +98,16 @@
compileTestSet(new File(TEST262_SUITE_DIR), new TestFilter() {
@Override
public boolean exclude(final File file, final String content) {
- return content.indexOf("@negative") != -1;
+ return content != null && content.contains("@negative");
}
});
}
- compileTestSet(new File(TEST_BASIC_DIR), null);
+ compileTestSet(new File(TEST_BASIC_DIR), new TestFilter() {
+ @Override
+ public boolean exclude(final File file, final String content) {
+ return file.getName().equals("es6");
+ }
+ });
compileTestSet(new File(TEST_NODE_DIR, "node"), null);
compileTestSet(new File(TEST_NODE_DIR, "src"), null);
}
@@ -136,6 +141,9 @@
private int skipped;
private void compileJSDirectory(final File dir, final TestFilter filter) {
+ if (filter != null && filter.exclude(dir, null)) {
+ return;
+ }
for (final File f : dir.listFiles()) {
if (f.isDirectory()) {
compileJSDirectory(f, filter);
--- a/nashorn/test/src/jdk/nashorn/internal/parser/ParserTest.java Thu Sep 04 13:26:26 2014 -0700
+++ b/nashorn/test/src/jdk/nashorn/internal/parser/ParserTest.java Wed Jul 05 19:59:54 2017 +0200
@@ -82,11 +82,16 @@
parseTestSet(TEST262_SUITE_DIR, new TestFilter() {
@Override
public boolean exclude(final File file, final String content) {
- return content.indexOf("@negative") != -1;
+ return content != null && content.contains("@negative");
}
});
}
- parseTestSet(TEST_BASIC_DIR, null);
+ parseTestSet(TEST_BASIC_DIR, new TestFilter() {
+ @Override
+ public boolean exclude(final File file, final String content) {
+ return file.getName().equals("es6");
+ }
+ });
}
private void parseTestSet(final String testSet, final TestFilter filter) {
@@ -120,6 +125,9 @@
private int skipped;
private void parseJSDirectory(final File dir, final TestFilter filter) {
+ if (filter != null && filter.exclude(dir, null)) {
+ return;
+ }
for (final File f : dir.listFiles()) {
if (f.isDirectory()) {
parseJSDirectory(f, filter);