# HG changeset patch # User duke # Date 1499277594 -7200 # Node ID b764fbee45e2d6497b5a6719368fbd7fef0a40ca # Parent bbce32388a2d34a929c09a408e83001b847d69fd# Parent 436d37b20f8daad04c6a96f8e0eb4b6dcfd42646 Merge diff -r bbce32388a2d -r b764fbee45e2 .hgtags-top-repo --- 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 diff -r bbce32388a2d -r b764fbee45e2 corba/.hgtags --- 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 diff -r bbce32388a2d -r b764fbee45e2 hotspot/.hgtags --- 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 diff -r bbce32388a2d -r b764fbee45e2 hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java --- 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 heapRegionIterator() { - return hrs().heapRegionIterator(); + return hrm().heapRegionIterator(); } public void heapRegionIterate(SpaceClosure scl) { diff -r bbce32388a2d -r b764fbee45e2 hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionManager.java --- /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 heapRegionIterator() { + return regions().heapRegionIterator(length()); + } + + public HeapRegionManager(Address addr) { + super(addr); + } +} diff -r bbce32388a2d -r b764fbee45e2 hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSeq.java --- 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 heapRegionIterator() { - return regions().heapRegionIterator(length()); - } - - public HeapRegionSeq(Address addr) { - super(addr); - } -} diff -r bbce32388a2d -r b764fbee45e2 hotspot/make/Makefile --- 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 # diff -r bbce32388a2d -r b764fbee45e2 hotspot/make/jprt.gmk --- 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 + diff -r bbce32388a2d -r b764fbee45e2 hotspot/make/jprt.properties --- 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= \ diff -r bbce32388a2d -r b764fbee45e2 hotspot/make/windows/makefiles/vm.make --- 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" diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/cpu/x86/vm/vm_version_x86.cpp --- 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. diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/cpu/x86/vm/vm_version_x86.hpp --- 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 diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/os/windows/vm/os_windows.cpp --- 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; } diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/tools/ProjectCreator/BuildConfig.java --- 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(); diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC10.java --- 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; } diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC7.java --- 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); diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC8.java --- 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); diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- 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(), diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp --- 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) ? " (*)" : "", diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp --- 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(); diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp --- 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()); diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp --- 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 diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp --- 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); diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp --- 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 diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- 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 diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- 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; diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp --- 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 @@ -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 @@ -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(); } diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp --- 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" diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp --- 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), diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp --- 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; diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.cpp --- /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 + diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/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.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 { + 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 { + 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 + diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.inline.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 diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp --- 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(); } diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp --- 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 - diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp --- 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 { - 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 { - 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 - diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.inline.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 diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp --- 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, diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp --- 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. diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp --- 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(); } diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp --- 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); diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp --- 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) \ diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/parallelScavenge/psGenerationCounters.cpp --- 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, diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/parallelScavenge/psGenerationCounters.hpp --- 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"); diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp --- 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); diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp --- 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(); diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/shared/generationCounters.cpp --- 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, diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/gc_implementation/shared/generationCounters.hpp --- 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); diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/memory/defNewGeneration.cpp --- 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, diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/memory/filemap.cpp --- 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); } } diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/memory/filemap.hpp --- 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); diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/memory/metaspace.cpp --- 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); diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/memory/metaspaceShared.cpp --- 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); + } + } +} diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/memory/metaspaceShared.hpp --- 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 diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/memory/tenuredGeneration.cpp --- 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); diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/oops/instanceKlass.cpp --- 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" diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/oops/instanceMirrorKlass.cpp --- 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" diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/oops/instanceRefKlass.cpp --- 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" diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/oops/objArrayKlass.cpp --- 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" diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/opto/type.cpp --- 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; diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/opto/type.hpp --- 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; diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/runtime/java.cpp --- 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; diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/services/mallocTracker.hpp --- 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(this); + return s->by_type(mtThreadStack)->malloc_count(); } void reset(); diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/services/memBaseline.cpp --- 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 - _malloc_sites; + SortedLinkedList _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 + SortedLinkedList _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 - allocation_sites(arena()); + SortedLinkedList 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 - tmp(arena()); + SortedLinkedList 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 - tmp(arena()); + SortedLinkedList 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 - tmp(arena()); + SortedLinkedList 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 - tmp(arena()); + SortedLinkedList tmp; - tmp.add(&_virtual_memory_sites); + tmp.move(&_virtual_memory_sites); _virtual_memory_sites.set_head(tmp.head()); tmp.set_head(NULL); diff -r bbce32388a2d -r b764fbee45e2 hotspot/src/share/vm/services/memBaseline.hpp --- 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 - _malloc_sites; + LinkedListImpl _malloc_sites; // All virtual memory allocations - LinkedListImpl - _virtual_memory_allocations; + LinkedListImpl _virtual_memory_allocations; // Virtual memory allocations by allocation sites, always in by_address // order - LinkedListImpl - _virtual_memory_sites; + LinkedListImpl _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(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(); diff -r bbce32388a2d -r b764fbee45e2 hotspot/test/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java --- 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 { diff -r bbce32388a2d -r b764fbee45e2 hotspot/test/compiler/classUnloading/methodUnloading/TestMethodUnloading.java --- 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"; diff -r bbce32388a2d -r b764fbee45e2 hotspot/test/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnSupportedConfig.java --- 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")); } diff -r bbce32388a2d -r b764fbee45e2 hotspot/test/compiler/rtm/cli/TestUseRTMDeoptOptionOnSupportedConfig.java --- 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 { diff -r bbce32388a2d -r b764fbee45e2 hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnSupportedConfig.java --- 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 { diff -r bbce32388a2d -r b764fbee45e2 hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionWithBiasedLocking.java --- 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 { diff -r bbce32388a2d -r b764fbee45e2 hotspot/test/gc/g1/TestHumongousShrinkHeap.java --- 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 diff -r bbce32388a2d -r b764fbee45e2 hotspot/test/gc/g1/TestStringDeduplicationTools.java --- 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 list, int uniqueExpected) { - for (;;) { + boolean passed = false; + for (int attempts = 0; attempts < 10; attempts++) { // Check number of deduplicated strings ArrayList unique = new ArrayList(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); diff -r bbce32388a2d -r b764fbee45e2 hotspot/test/gc/whitebox/TestWBGC.java --- /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)); + } + } +} diff -r bbce32388a2d -r b764fbee45e2 hotspot/test/runtime/CompressedOops/CompressedClassPointers.java --- 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); } diff -r bbce32388a2d -r b764fbee45e2 hotspot/test/runtime/NMT/CommandLineEmptyArgument.java --- 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.*; diff -r bbce32388a2d -r b764fbee45e2 hotspot/test/runtime/NMT/JcmdDetailDiff.java --- 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"}); diff -r bbce32388a2d -r b764fbee45e2 hotspot/test/runtime/NMT/MallocSiteHashOverflow.java --- 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 diff -r bbce32388a2d -r b764fbee45e2 hotspot/test/runtime/NMT/MallocStressTest.java --- 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 diff -r bbce32388a2d -r b764fbee45e2 hotspot/test/runtime/NMT/NMTWithCDS.java --- 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); diff -r bbce32388a2d -r b764fbee45e2 hotspot/test/runtime/NMT/VirtualAllocCommitUncommitRecommit.java --- 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"); } } diff -r bbce32388a2d -r b764fbee45e2 hotspot/test/runtime/jsig/Test8017498.sh --- 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 diff -r bbce32388a2d -r b764fbee45e2 jdk/.hgtags --- 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 diff -r bbce32388a2d -r b764fbee45e2 jdk/make/CreateJars.gmk --- 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)) diff -r bbce32388a2d -r b764fbee45e2 jdk/make/copy/Copy-java.desktop.gmk --- 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. # diff -r bbce32388a2d -r b764fbee45e2 jdk/make/data/currency/CurrencyData.properties --- 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 diff -r bbce32388a2d -r b764fbee45e2 jdk/make/gensrc/GensrcLocaleDataMetaInfo.gmk --- 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 ################################################################################ diff -r bbce32388a2d -r b764fbee45e2 jdk/make/profile-includes.txt --- 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 \ diff -r bbce32388a2d -r b764fbee45e2 jdk/make/src/classes/build/tools/cldrconverter/CLDRConverter.java --- 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); diff -r bbce32388a2d -r b764fbee45e2 jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java --- 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}"); } } diff -r bbce32388a2d -r b764fbee45e2 jdk/src/demo/share/java2d/J2DBench/Makefile --- 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) diff -r bbce32388a2d -r b764fbee45e2 jdk/src/demo/share/java2d/J2DBench/README --- 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. diff -r bbce32388a2d -r b764fbee45e2 jdk/src/demo/share/java2d/J2DBench/build.xml --- 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 @@ - + All async 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}. * *
  • 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 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 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 + 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 extends Completion { + Executor executor; // executor to use (null if none) + CompletableFuture dep; // the dependent to complete + CompletableFuture src; // source for action + + UniCompletion(Executor executor, CompletableFuture dep, + CompletableFuture 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 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 extends UniCompletion { + Function fn; + UniApply(Executor executor, CompletableFuture dep, + CompletableFuture src, + Function fn) { + super(executor, dep, src); this.fn = fn; + } + final CompletableFuture tryFire(int mode) { + CompletableFuture d; CompletableFuture 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 boolean uniApply(CompletableFuture a, + Function f, + UniApply 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 CompletableFuture uniApplyStage( + Executor e, Function f) { + if (f == null) throw new NullPointerException(); + CompletableFuture d = new CompletableFuture(); + if (e != null || !d.uniApply(this, f, null)) { + UniApply c = new UniApply(e, d, this, f); + push(c); + c.tryFire(SYNC); + } + return d; + } + + @SuppressWarnings("serial") + static final class UniAccept extends UniCompletion { + Consumer fn; + UniAccept(Executor executor, CompletableFuture dep, + CompletableFuture src, Consumer fn) { + super(executor, dep, src); this.fn = fn; + } + final CompletableFuture tryFire(int mode) { + CompletableFuture d; CompletableFuture 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 boolean uniAccept(CompletableFuture a, + Consumer f, UniAccept 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 uniAcceptStage(Executor e, + Consumer f) { + if (f == null) throw new NullPointerException(); + CompletableFuture d = new CompletableFuture(); + if (e != null || !d.uniAccept(this, f, null)) { + UniAccept c = new UniAccept(e, d, this, f); + push(c); + c.tryFire(SYNC); + } + return d; + } + + @SuppressWarnings("serial") + static final class UniRun extends UniCompletion { + Runnable fn; + UniRun(Executor executor, CompletableFuture dep, + CompletableFuture src, Runnable fn) { + super(executor, dep, src); this.fn = fn; + } + final CompletableFuture tryFire(int mode) { + CompletableFuture d; CompletableFuture 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 uniRunStage(Executor e, Runnable f) { + if (f == null) throw new NullPointerException(); + CompletableFuture d = new CompletableFuture(); + if (e != null || !d.uniRun(this, f, null)) { + UniRun c = new UniRun(e, d, this, f); + push(c); + c.tryFire(SYNC); + } + return d; + } + + @SuppressWarnings("serial") + static final class UniWhenComplete extends UniCompletion { + BiConsumer fn; + UniWhenComplete(Executor executor, CompletableFuture dep, + CompletableFuture src, + BiConsumer fn) { + super(executor, dep, src); this.fn = fn; + } + final CompletableFuture tryFire(int mode) { + CompletableFuture d; CompletableFuture 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 a, + BiConsumer f, + UniWhenComplete 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 uniWhenCompleteStage( + Executor e, BiConsumer f) { + if (f == null) throw new NullPointerException(); + CompletableFuture d = new CompletableFuture(); + if (e != null || !d.uniWhenComplete(this, f, null)) { + UniWhenComplete c = new UniWhenComplete(e, d, this, f); + push(c); + c.tryFire(SYNC); + } + return d; + } + + @SuppressWarnings("serial") + static final class UniHandle extends UniCompletion { + BiFunction fn; + UniHandle(Executor executor, CompletableFuture dep, + CompletableFuture src, + BiFunction fn) { + super(executor, dep, src); this.fn = fn; + } + final CompletableFuture tryFire(int mode) { + CompletableFuture d; CompletableFuture 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 boolean uniHandle(CompletableFuture a, + BiFunction f, + UniHandle 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 CompletableFuture uniHandleStage( + Executor e, BiFunction f) { + if (f == null) throw new NullPointerException(); + CompletableFuture d = new CompletableFuture(); + if (e != null || !d.uniHandle(this, f, null)) { + UniHandle c = new UniHandle(e, d, this, f); + push(c); + c.tryFire(SYNC); + } + return d; + } + + @SuppressWarnings("serial") + static final class UniExceptionally extends UniCompletion { + Function fn; + UniExceptionally(CompletableFuture dep, CompletableFuture src, + Function fn) { + super(null, dep, src); this.fn = fn; + } + final CompletableFuture tryFire(int mode) { // never ASYNC + // assert mode != ASYNC; + CompletableFuture d; CompletableFuture 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 a, + Function f, + UniExceptionally 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 uniExceptionallyStage( + Function f) { + if (f == null) throw new NullPointerException(); + CompletableFuture d = new CompletableFuture(); + if (!d.uniExceptionally(this, f, null)) { + UniExceptionally c = new UniExceptionally(d, this, f); + push(c); + c.tryFire(SYNC); + } + return d; + } + + @SuppressWarnings("serial") + static final class UniRelay extends UniCompletion { // for Compose + UniRelay(CompletableFuture dep, CompletableFuture src) { + super(null, dep, src); + } + final CompletableFuture tryFire(int mode) { + CompletableFuture d; CompletableFuture a; + if ((d = dep) == null || !d.uniRelay(a = src)) + return null; + src = null; dep = null; + return d.postFire(a, mode); + } + } + + final boolean uniRelay(CompletableFuture 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 extends UniCompletion { + Function> fn; + UniCompose(Executor executor, CompletableFuture dep, + CompletableFuture src, + Function> fn) { + super(executor, dep, src); this.fn = fn; + } + final CompletableFuture tryFire(int mode) { + CompletableFuture d; CompletableFuture 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 boolean uniCompose( + CompletableFuture a, + Function> f, + UniCompose 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 g = f.apply(s).toCompletableFuture(); + if (g.result == null || !uniRelay(g)) { + UniRelay copy = new UniRelay(this, g); + g.push(copy); + copy.tryFire(SYNC); + if (result == null) + return false; + } + } catch (Throwable ex) { + completeThrowable(ex); + } + } + return true; + } + + private CompletableFuture uniComposeStage( + Executor e, Function> 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(encodeThrowable(x, r)); + } + r = null; + } + try { + @SuppressWarnings("unchecked") T t = (T) r; + return f.apply(t).toCompletableFuture(); + } catch (Throwable ex) { + return new CompletableFuture(encodeThrowable(ex)); + } + } + CompletableFuture d = new CompletableFuture(); + UniCompose c = new UniCompose(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 extends UniCompletion { + CompletableFuture snd; // second source for action + BiCompletion(Executor executor, CompletableFuture dep, + CompletableFuture src, CompletableFuture 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 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 extends BiCompletion { + BiFunction fn; + BiApply(Executor executor, CompletableFuture dep, + CompletableFuture src, CompletableFuture snd, + BiFunction fn) { + super(executor, dep, src, snd); this.fn = fn; + } + final CompletableFuture tryFire(int mode) { + CompletableFuture d; + CompletableFuture a; + CompletableFuture 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 boolean biApply(CompletableFuture a, + CompletableFuture b, + BiFunction f, + BiApply 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 CompletableFuture biApplyStage( + Executor e, CompletionStage o, + BiFunction f) { + CompletableFuture b; + if (f == null || (b = o.toCompletableFuture()) == null) + throw new NullPointerException(); + CompletableFuture d = new CompletableFuture(); + if (e != null || !d.biApply(this, b, f, null)) { + BiApply c = new BiApply(e, d, this, b, f); + bipush(b, c); + c.tryFire(SYNC); + } + return d; + } + + @SuppressWarnings("serial") + static final class BiAccept extends BiCompletion { + BiConsumer fn; + BiAccept(Executor executor, CompletableFuture dep, + CompletableFuture src, CompletableFuture snd, + BiConsumer fn) { + super(executor, dep, src, snd); this.fn = fn; + } + final CompletableFuture tryFire(int mode) { + CompletableFuture d; + CompletableFuture a; + CompletableFuture 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 boolean biAccept(CompletableFuture a, + CompletableFuture b, + BiConsumer f, + BiAccept 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 CompletableFuture biAcceptStage( + Executor e, CompletionStage o, + BiConsumer f) { + CompletableFuture b; + if (f == null || (b = o.toCompletableFuture()) == null) + throw new NullPointerException(); + CompletableFuture d = new CompletableFuture(); + if (e != null || !d.biAccept(this, b, f, null)) { + BiAccept c = new BiAccept(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 extends BiCompletion { + Runnable fn; + BiRun(Executor executor, CompletableFuture dep, + CompletableFuture src, + CompletableFuture snd, + Runnable fn) { + super(executor, dep, src, snd); this.fn = fn; + } + final CompletableFuture tryFire(int mode) { + CompletableFuture d; + CompletableFuture a; + CompletableFuture 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 biRunStage(Executor e, CompletionStage o, + Runnable f) { + CompletableFuture b; + if (f == null || (b = o.toCompletableFuture()) == null) + throw new NullPointerException(); + CompletableFuture d = new CompletableFuture(); + if (e != null || !d.biRun(this, b, f, null)) { + BiRun c = new BiRun<>(e, d, this, b, f); + bipush(b, c); + c.tryFire(SYNC); + } + return d; + } + + @SuppressWarnings("serial") + static final class BiRelay extends BiCompletion { // for And + BiRelay(CompletableFuture dep, + CompletableFuture src, + CompletableFuture snd) { + super(null, dep, src, snd); + } + final CompletableFuture tryFire(int mode) { + CompletableFuture d; + CompletableFuture a; + CompletableFuture 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 andTree(CompletableFuture[] cfs, + int lo, int hi) { + CompletableFuture d = new CompletableFuture(); + 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 extends BiCompletion { + Function fn; + OrApply(Executor executor, CompletableFuture dep, + CompletableFuture src, + CompletableFuture snd, + Function fn) { + super(executor, dep, src, snd); this.fn = fn; + } + final CompletableFuture tryFire(int mode) { + CompletableFuture d; + CompletableFuture a; + CompletableFuture 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 boolean orApply(CompletableFuture a, + CompletableFuture b, + Function f, + OrApply 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 CompletableFuture orApplyStage( + Executor e, CompletionStage o, + Function f) { + CompletableFuture b; + if (f == null || (b = o.toCompletableFuture()) == null) + throw new NullPointerException(); + CompletableFuture d = new CompletableFuture(); + if (e != null || !d.orApply(this, b, f, null)) { + OrApply c = new OrApply(e, d, this, b, f); + orpush(b, c); + c.tryFire(SYNC); + } + return d; + } + + @SuppressWarnings("serial") + static final class OrAccept extends BiCompletion { + Consumer fn; + OrAccept(Executor executor, CompletableFuture dep, + CompletableFuture src, + CompletableFuture snd, + Consumer fn) { + super(executor, dep, src, snd); this.fn = fn; + } + final CompletableFuture tryFire(int mode) { + CompletableFuture d; + CompletableFuture a; + CompletableFuture 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 boolean orAccept(CompletableFuture a, + CompletableFuture b, + Consumer f, + OrAccept 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 CompletableFuture orAcceptStage( + Executor e, CompletionStage o, Consumer f) { + CompletableFuture b; + if (f == null || (b = o.toCompletableFuture()) == null) + throw new NullPointerException(); + CompletableFuture d = new CompletableFuture(); + if (e != null || !d.orAccept(this, b, f, null)) { + OrAccept c = new OrAccept(e, d, this, b, f); + orpush(b, c); + c.tryFire(SYNC); + } + return d; + } + + @SuppressWarnings("serial") + static final class OrRun extends BiCompletion { + Runnable fn; + OrRun(Executor executor, CompletableFuture dep, + CompletableFuture src, + CompletableFuture snd, + Runnable fn) { + super(executor, dep, src, snd); this.fn = fn; + } + final CompletableFuture tryFire(int mode) { + CompletableFuture d; + CompletableFuture a; + CompletableFuture 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 orRunStage(Executor e, CompletionStage o, + Runnable f) { + CompletableFuture b; + if (f == null || (b = o.toCompletableFuture()) == null) + throw new NullPointerException(); + CompletableFuture d = new CompletableFuture(); + if (e != null || !d.orRun(this, b, f, null)) { + OrRun c = new OrRun<>(e, d, this, b, f); + orpush(b, c); + c.tryFire(SYNC); + } + return d; + } + + @SuppressWarnings("serial") + static final class OrRelay extends BiCompletion { // for Or + OrRelay(CompletableFuture dep, CompletableFuture src, + CompletableFuture snd) { + super(null, dep, src, snd); + } + final CompletableFuture tryFire(int mode) { + CompletableFuture d; + CompletableFuture a; + CompletableFuture 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 orTree(CompletableFuture[] cfs, + int lo, int hi) { + CompletableFuture d = new CompletableFuture(); + 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 extends ForkJoinTask + implements Runnable, AsynchronousCompletionTask { + CompletableFuture dep; Supplier fn; + AsyncSupply(CompletableFuture dep, Supplier 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 d; Supplier 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 CompletableFuture asyncSupplyStage(Executor e, + Supplier f) { + if (f == null) throw new NullPointerException(); + CompletableFuture d = new CompletableFuture(); + e.execute(new AsyncSupply(d, f)); + return d; + } + + @SuppressWarnings("serial") + static final class AsyncRun extends ForkJoinTask + implements Runnable, AsynchronousCompletionTask { + CompletableFuture dep; Runnable fn; + AsyncRun(CompletableFuture 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 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 asyncRunStage(Executor e, Runnable f) { + if (f == null) throw new NullPointerException(); + CompletableFuture d = new CompletableFuture(); + 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 - 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 dst; - AsyncRun(Runnable fn, CompletableFuture dst) { - this.fn = fn; this.dst = dst; - } - public final boolean exec() { - CompletableFuture 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 extends Async { - final Supplier fn; - final CompletableFuture dst; - AsyncSupply(Supplier fn, CompletableFuture dst) { - this.fn = fn; this.dst = dst; - } - public final boolean exec() { - CompletableFuture 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 extends Async { - final T arg; - final Function fn; - final CompletableFuture dst; - AsyncApply(T arg, Function fn, - CompletableFuture dst) { - this.arg = arg; this.fn = fn; this.dst = dst; - } - public final boolean exec() { - CompletableFuture 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 extends Async { - final T arg1; - final U arg2; - final BiFunction fn; - final CompletableFuture dst; - AsyncCombine(T arg1, U arg2, - BiFunction fn, - CompletableFuture dst) { - this.arg1 = arg1; this.arg2 = arg2; this.fn = fn; this.dst = dst; - } - public final boolean exec() { - CompletableFuture 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 extends Async { - final T arg; - final Consumer fn; - final CompletableFuture dst; - AsyncAccept(T arg, Consumer 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 extends Async { - final T arg1; - final U arg2; - final BiConsumer fn; - final CompletableFuture dst; - AsyncAcceptBoth(T arg1, U arg2, - BiConsumer 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 extends Async { - final T arg; - final Function> fn; - final CompletableFuture dst; - AsyncCompose(T arg, - Function> fn, - CompletableFuture dst) { - this.arg = arg; this.fn = fn; this.dst = dst; - } - public final boolean exec() { - CompletableFuture d, fr; U u; Throwable ex; - if ((d = this.dst) != null && d.result == null) { - try { - CompletionStage 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 extends Async { - final T arg1; - final Throwable arg2; - final BiConsumer fn; - final CompletableFuture dst; - AsyncWhenComplete(T arg1, Throwable arg2, - BiConsumer fn, - CompletableFuture dst) { - this.arg1 = arg1; this.arg2 = arg2; this.fn = fn; this.dst = dst; - } - public final boolean exec() { - CompletableFuture 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 extends Completion { - final CompletableFuture src; - final Function fn; - final CompletableFuture dst; - final Executor executor; - ThenApply(CompletableFuture src, - Function fn, - CompletableFuture dst, - Executor executor) { - this.src = src; this.fn = fn; this.dst = dst; - this.executor = executor; - } - public final void run() { - final CompletableFuture a; - final Function 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; - U u = null; - if (ex == null) { - try { - if (e != null) - execAsync(e, new AsyncApply(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 extends Completion { - final CompletableFuture src; - final Consumer fn; - final CompletableFuture dst; - final Executor executor; - ThenAccept(CompletableFuture src, - Consumer fn, - CompletableFuture dst, - Executor executor) { - this.src = src; this.fn = fn; this.dst = dst; - this.executor = executor; - } - public final void run() { - final CompletableFuture a; - final Consumer 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, 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 dst; - final Executor executor; - ThenRun(CompletableFuture src, - Runnable fn, - CompletableFuture 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 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 extends Completion { - final CompletableFuture src; - final CompletableFuture snd; - final BiFunction fn; - final CompletableFuture dst; - final Executor executor; - ThenCombine(CompletableFuture src, - CompletableFuture snd, - BiFunction fn, - CompletableFuture 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 BiFunction fn; - final CompletableFuture 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, 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 extends Completion { - final CompletableFuture src; - final CompletableFuture snd; - final BiConsumer fn; - final CompletableFuture dst; - final Executor executor; - ThenAcceptBoth(CompletableFuture src, - CompletableFuture snd, - BiConsumer fn, - CompletableFuture 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 BiConsumer fn; - final CompletableFuture 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, 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 dst; - final Executor executor; - RunAfterBoth(CompletableFuture src, - CompletableFuture snd, - Runnable fn, - CompletableFuture 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 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 dst; - AndCompletion(CompletableFuture src, - CompletableFuture snd, - CompletableFuture dst) { - this.src = src; this.snd = snd; this.dst = dst; - } - public final void run() { - final CompletableFuture a; - final CompletableFuture b; - final CompletableFuture 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 extends Completion { - final CompletableFuture src; - final CompletableFuture snd; - final Function fn; - final CompletableFuture dst; - final Executor executor; - ApplyToEither(CompletableFuture src, - CompletableFuture snd, - Function fn, - CompletableFuture 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 Function 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) || - ((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, 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 extends Completion { - final CompletableFuture src; - final CompletableFuture snd; - final Consumer fn; - final CompletableFuture dst; - final Executor executor; - AcceptEither(CompletableFuture src, - CompletableFuture snd, - Consumer fn, - CompletableFuture 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 Consumer 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) || - ((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, 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 dst; - final Executor executor; - RunAfterEither(CompletableFuture src, - CompletableFuture snd, - Runnable fn, - CompletableFuture 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 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 dst; - OrCompletion(CompletableFuture src, - CompletableFuture snd, - CompletableFuture dst) { - this.src = src; this.snd = snd; this.dst = dst; - } - public final void run() { - final CompletableFuture a; - final CompletableFuture b; - final CompletableFuture 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 extends Completion { - final CompletableFuture src; - final Function fn; - final CompletableFuture dst; - ExceptionCompletion(CompletableFuture src, - Function fn, - CompletableFuture dst) { - this.src = src; this.fn = fn; this.dst = dst; - } - public final void run() { - final CompletableFuture a; - final Function fn; - final CompletableFuture 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 extends Completion { - final CompletableFuture src; - final BiConsumer fn; - final CompletableFuture dst; - final Executor executor; - WhenCompleteCompletion(CompletableFuture src, - BiConsumer fn, - CompletableFuture dst, - Executor executor) { - this.src = src; this.fn = fn; this.dst = dst; - this.executor = executor; - } - public final void run() { - final CompletableFuture a; - final BiConsumer 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; - Throwable dx = null; + else if (q.thread != null && result == null) { try { - if (e != null) - execAsync(e, new AsyncWhenComplete(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 extends Completion { - final CompletableFuture src; - final CompletableFuture dst; - ThenCopy(CompletableFuture src, - CompletableFuture dst) { - this.src = src; this.dst = dst; - } - public final void run() { - final CompletableFuture a; - final CompletableFuture 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 dst - static final class ThenPropagate extends Completion { - final CompletableFuture src; - final CompletableFuture dst; - ThenPropagate(CompletableFuture src, - CompletableFuture dst) { - this.src = src; this.dst = dst; - } - public final void run() { - final CompletableFuture a; - final CompletableFuture 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 extends Completion { - final CompletableFuture src; - final BiFunction fn; - final CompletableFuture dst; - final Executor executor; - HandleCompletion(CompletableFuture src, - BiFunction fn, - CompletableFuture dst, - Executor executor) { - this.src = src; this.fn = fn; this.dst = dst; - this.executor = executor; - } - public final void run() { - final CompletableFuture a; - final BiFunction 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; - U u = null; - Throwable dx = null; - try { - if (e != null) - execAsync(e, new AsyncCombine(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 extends Completion { - final CompletableFuture src; - final Function> fn; - final CompletableFuture dst; - final Executor executor; - ThenCompose(CompletableFuture src, - Function> fn, - CompletableFuture dst, - Executor executor) { - this.src = src; this.fn = fn; this.dst = dst; - this.executor = executor; - } - public final void run() { - final CompletableFuture a; - final Function> fn; - final CompletableFuture 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 c = null; - U u = null; - boolean complete = false; - if (ex == null) { - if ((e = executor) != null) - execAsync(e, new AsyncCompose(t, fn, dst)); - else { - try { - CompletionStage 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 d = null; - Object s; - if ((s = c.result) == null) { - CompletionNode p = new CompletionNode - (d = new ThenCopy(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 CompletableFuture doThenApply - (Function fn, - Executor e) { - if (fn == null) throw new NullPointerException(); - CompletableFuture dst = new CompletableFuture(); - ThenApply d = null; - Object r; - if ((r = result) == null) { - CompletionNode p = new CompletionNode - (d = new ThenApply(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, 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 doThenAccept(Consumer fn, - Executor e) { - if (fn == null) throw new NullPointerException(); - CompletableFuture dst = new CompletableFuture(); - ThenAccept d = null; - Object r; - if ((r = result) == null) { - CompletionNode p = new CompletionNode - (d = new ThenAccept(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, 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 doThenRun(Runnable action, - Executor e) { - if (action == null) throw new NullPointerException(); - CompletableFuture dst = new CompletableFuture(); - 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 CompletableFuture doThenCombine - (CompletableFuture other, - BiFunction fn, - Executor e) { - if (other == null || fn == null) throw new NullPointerException(); - CompletableFuture dst = new CompletableFuture(); - ThenCombine d = null; - Object r, s = null; - if ((r = result) == null || (s = other.result) == null) { - d = new ThenCombine(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, 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 CompletableFuture doThenAcceptBoth - (CompletableFuture other, - BiConsumer fn, - Executor e) { - if (other == null || fn == null) throw new NullPointerException(); - CompletableFuture dst = new CompletableFuture(); - ThenAcceptBoth d = null; - Object r, s = null; - if ((r = result) == null || (s = other.result) == null) { - d = new ThenAcceptBoth(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, 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 doRunAfterBoth(CompletableFuture other, - Runnable action, - Executor e) { - if (other == null || action == null) throw new NullPointerException(); - CompletableFuture dst = new CompletableFuture(); - 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 CompletableFuture doApplyToEither - (CompletableFuture other, - Function fn, - Executor e) { - if (other == null || fn == null) throw new NullPointerException(); - CompletableFuture dst = new CompletableFuture(); - ApplyToEither d = null; - Object r; - if ((r = result) == null && (r = other.result) == null) { - d = new ApplyToEither(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, 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 doAcceptEither - (CompletableFuture other, - Consumer fn, - Executor e) { - if (other == null || fn == null) throw new NullPointerException(); - CompletableFuture dst = new CompletableFuture(); - AcceptEither d = null; - Object r; - if ((r = result) == null && (r = other.result) == null) { - d = new AcceptEither(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, 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 doRunAfterEither - (CompletableFuture other, - Runnable action, - Executor e) { - if (other == null || action == null) throw new NullPointerException(); - CompletableFuture dst = new CompletableFuture(); - 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 CompletableFuture doThenCompose - (Function> fn, - Executor e) { - if (fn == null) throw new NullPointerException(); - CompletableFuture dst = null; - ThenCompose d = null; - Object r; - if ((r = result) == null) { - dst = new CompletableFuture(); - CompletionNode p = new CompletionNode - (d = new ThenCompose(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(); - execAsync(e, new AsyncCompose(t, fn, dst)); - } - else { - try { - CompletionStage 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(); - if (ex != null) - dst.internalComplete(null, ex); - } - helpPostComplete(); - dst.helpPostComplete(); - return dst; - } - - private CompletableFuture doWhenComplete - (BiConsumer fn, - Executor e) { - if (fn == null) throw new NullPointerException(); - CompletableFuture dst = new CompletableFuture(); - WhenCompleteCompletion d = null; - Object r; - if ((r = result) == null) { - CompletionNode p = - new CompletionNode(d = new WhenCompleteCompletion - (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, 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 CompletableFuture doHandle - (BiFunction fn, - Executor e) { - if (fn == null) throw new NullPointerException(); - CompletableFuture dst = new CompletableFuture(); - HandleCompletion d = null; - Object r; - if ((r = result) == null) { - CompletionNode p = - new CompletionNode(d = new HandleCompletion - (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, 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 CompletableFuture supplyAsync(Supplier supplier) { - if (supplier == null) throw new NullPointerException(); - CompletableFuture f = new CompletableFuture(); - execAsync(ForkJoinPool.commonPool(), new AsyncSupply(supplier, f)); - return f; + return asyncSupplyStage(asyncPool, supplier); } /** @@ -2143,11 +1819,7 @@ */ public static CompletableFuture supplyAsync(Supplier supplier, Executor executor) { - if (executor == null || supplier == null) - throw new NullPointerException(); - CompletableFuture f = new CompletableFuture(); - execAsync(executor, new AsyncSupply(supplier, f)); - return f; + return asyncSupplyStage(screenExecutor(executor), supplier); } /** @@ -2160,10 +1832,7 @@ * @return the new CompletableFuture */ public static CompletableFuture runAsync(Runnable runnable) { - if (runnable == null) throw new NullPointerException(); - CompletableFuture f = new CompletableFuture(); - execAsync(ForkJoinPool.commonPool(), new AsyncRun(runnable, f)); - return f; + return asyncRunStage(asyncPool, runnable); } /** @@ -2178,11 +1847,7 @@ */ public static CompletableFuture runAsync(Runnable runnable, Executor executor) { - if (executor == null || runnable == null) - throw new NullPointerException(); - CompletableFuture f = new CompletableFuture(); - execAsync(executor, new AsyncRun(runnable, f)); - return f; + return asyncRunStage(screenExecutor(executor), runnable); } /** @@ -2194,9 +1859,7 @@ * @return the completed CompletableFuture */ public static CompletableFuture completedFuture(U value) { - CompletableFuture f = new CompletableFuture(); - f.result = (value == null) ? NIL : value; - return f; + return new CompletableFuture((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 CompletableFuture thenApply - (Function fn) { - return doThenApply(fn, null); + public CompletableFuture thenApply( + Function fn) { + return uniApplyStage(null, fn); } - public CompletableFuture thenApplyAsync - (Function fn) { - return doThenApply(fn, ForkJoinPool.commonPool()); + public CompletableFuture thenApplyAsync( + Function fn) { + return uniApplyStage(asyncPool, fn); } - public CompletableFuture thenApplyAsync - (Function fn, - Executor executor) { - if (executor == null) throw new NullPointerException(); - return doThenApply(fn, executor); + public CompletableFuture thenApplyAsync( + Function fn, Executor executor) { + return uniApplyStage(screenExecutor(executor), fn); } - public CompletableFuture thenAccept - (Consumer action) { - return doThenAccept(action, null); + public CompletableFuture thenAccept(Consumer action) { + return uniAcceptStage(null, action); } - public CompletableFuture thenAcceptAsync - (Consumer action) { - return doThenAccept(action, ForkJoinPool.commonPool()); + public CompletableFuture thenAcceptAsync(Consumer action) { + return uniAcceptStage(asyncPool, action); } - public CompletableFuture thenAcceptAsync - (Consumer action, - Executor executor) { - if (executor == null) throw new NullPointerException(); - return doThenAccept(action, executor); + public CompletableFuture thenAcceptAsync(Consumer action, + Executor executor) { + return uniAcceptStage(screenExecutor(executor), action); } - public CompletableFuture thenRun - (Runnable action) { - return doThenRun(action, null); + public CompletableFuture thenRun(Runnable action) { + return uniRunStage(null, action); } - public CompletableFuture thenRunAsync - (Runnable action) { - return doThenRun(action, ForkJoinPool.commonPool()); + public CompletableFuture thenRunAsync(Runnable action) { + return uniRunStage(asyncPool, action); } - public CompletableFuture thenRunAsync - (Runnable action, - Executor executor) { - if (executor == null) throw new NullPointerException(); - return doThenRun(action, executor); + public CompletableFuture thenRunAsync(Runnable action, + Executor executor) { + return uniRunStage(screenExecutor(executor), action); } - public CompletableFuture thenCombine - (CompletionStage other, - BiFunction fn) { - return doThenCombine(other.toCompletableFuture(), fn, null); + public CompletableFuture thenCombine( + CompletionStage other, + BiFunction fn) { + return biApplyStage(null, other, fn); } - public CompletableFuture thenCombineAsync - (CompletionStage other, - BiFunction fn) { - return doThenCombine(other.toCompletableFuture(), fn, - ForkJoinPool.commonPool()); + public CompletableFuture thenCombineAsync( + CompletionStage other, + BiFunction fn) { + return biApplyStage(asyncPool, other, fn); } - public CompletableFuture thenCombineAsync - (CompletionStage other, - BiFunction fn, - Executor executor) { - if (executor == null) throw new NullPointerException(); - return doThenCombine(other.toCompletableFuture(), fn, executor); + public CompletableFuture thenCombineAsync( + CompletionStage other, + BiFunction fn, Executor executor) { + return biApplyStage(screenExecutor(executor), other, fn); } - public CompletableFuture thenAcceptBoth - (CompletionStage other, - BiConsumer action) { - return doThenAcceptBoth(other.toCompletableFuture(), action, null); + public CompletableFuture thenAcceptBoth( + CompletionStage other, + BiConsumer action) { + return biAcceptStage(null, other, action); } - public CompletableFuture thenAcceptBothAsync - (CompletionStage other, - BiConsumer action) { - return doThenAcceptBoth(other.toCompletableFuture(), action, - ForkJoinPool.commonPool()); + public CompletableFuture thenAcceptBothAsync( + CompletionStage other, + BiConsumer action) { + return biAcceptStage(asyncPool, other, action); } - public CompletableFuture thenAcceptBothAsync - (CompletionStage other, - BiConsumer action, - Executor executor) { - if (executor == null) throw new NullPointerException(); - return doThenAcceptBoth(other.toCompletableFuture(), action, executor); - } - - public CompletableFuture runAfterBoth - (CompletionStage other, - Runnable action) { - return doRunAfterBoth(other.toCompletableFuture(), action, null); + public CompletableFuture thenAcceptBothAsync( + CompletionStage other, + BiConsumer action, Executor executor) { + return biAcceptStage(screenExecutor(executor), other, action); } - public CompletableFuture runAfterBothAsync - (CompletionStage other, - Runnable action) { - return doRunAfterBoth(other.toCompletableFuture(), action, - ForkJoinPool.commonPool()); + public CompletableFuture runAfterBoth(CompletionStage other, + Runnable action) { + return biRunStage(null, other, action); } - public CompletableFuture runAfterBothAsync - (CompletionStage other, - Runnable action, - Executor executor) { - if (executor == null) throw new NullPointerException(); - return doRunAfterBoth(other.toCompletableFuture(), action, executor); + public CompletableFuture runAfterBothAsync(CompletionStage other, + Runnable action) { + return biRunStage(asyncPool, other, action); } - - public CompletableFuture applyToEither - (CompletionStage other, - Function fn) { - return doApplyToEither(other.toCompletableFuture(), fn, null); + public CompletableFuture runAfterBothAsync(CompletionStage other, + Runnable action, + Executor executor) { + return biRunStage(screenExecutor(executor), other, action); } - public CompletableFuture applyToEitherAsync - (CompletionStage other, - Function fn) { - return doApplyToEither(other.toCompletableFuture(), fn, - ForkJoinPool.commonPool()); + public CompletableFuture applyToEither( + CompletionStage other, Function fn) { + return orApplyStage(null, other, fn); + } + + public CompletableFuture applyToEitherAsync( + CompletionStage other, Function fn) { + return orApplyStage(asyncPool, other, fn); } - public CompletableFuture applyToEitherAsync - (CompletionStage other, - Function fn, - Executor executor) { - if (executor == null) throw new NullPointerException(); - return doApplyToEither(other.toCompletableFuture(), fn, executor); - } - - public CompletableFuture acceptEither - (CompletionStage other, - Consumer action) { - return doAcceptEither(other.toCompletableFuture(), action, null); + public CompletableFuture applyToEitherAsync( + CompletionStage other, Function fn, + Executor executor) { + return orApplyStage(screenExecutor(executor), other, fn); } - public CompletableFuture acceptEitherAsync - (CompletionStage other, - Consumer action) { - return doAcceptEither(other.toCompletableFuture(), action, - ForkJoinPool.commonPool()); + public CompletableFuture acceptEither( + CompletionStage other, Consumer action) { + return orAcceptStage(null, other, action); } - public CompletableFuture acceptEitherAsync - (CompletionStage other, - Consumer action, - Executor executor) { - if (executor == null) throw new NullPointerException(); - return doAcceptEither(other.toCompletableFuture(), action, executor); + public CompletableFuture acceptEitherAsync( + CompletionStage other, Consumer action) { + return orAcceptStage(asyncPool, other, action); + } + + public CompletableFuture acceptEitherAsync( + CompletionStage other, Consumer action, + Executor executor) { + return orAcceptStage(screenExecutor(executor), other, action); } public CompletableFuture runAfterEither(CompletionStage other, Runnable action) { - return doRunAfterEither(other.toCompletableFuture(), action, null); + return orRunStage(null, other, action); } - public CompletableFuture runAfterEitherAsync - (CompletionStage other, - Runnable action) { - return doRunAfterEither(other.toCompletableFuture(), action, - ForkJoinPool.commonPool()); + public CompletableFuture runAfterEitherAsync(CompletionStage other, + Runnable action) { + return orRunStage(asyncPool, other, action); } - public CompletableFuture runAfterEitherAsync - (CompletionStage other, - Runnable action, - Executor executor) { - if (executor == null) throw new NullPointerException(); - return doRunAfterEither(other.toCompletableFuture(), action, executor); + public CompletableFuture runAfterEitherAsync(CompletionStage other, + Runnable action, + Executor executor) { + return orRunStage(screenExecutor(executor), other, action); } - public CompletableFuture thenCompose - (Function> fn) { - return doThenCompose(fn, null); + public CompletableFuture thenCompose( + Function> fn) { + return uniComposeStage(null, fn); } - public CompletableFuture thenComposeAsync - (Function> fn) { - return doThenCompose(fn, ForkJoinPool.commonPool()); + public CompletableFuture thenComposeAsync( + Function> fn) { + return uniComposeStage(asyncPool, fn); } - public CompletableFuture thenComposeAsync - (Function> fn, - Executor executor) { - if (executor == null) throw new NullPointerException(); - return doThenCompose(fn, executor); + public CompletableFuture thenComposeAsync( + Function> fn, + Executor executor) { + return uniComposeStage(screenExecutor(executor), fn); } - public CompletableFuture whenComplete - (BiConsumer action) { - return doWhenComplete(action, null); + public CompletableFuture whenComplete( + BiConsumer action) { + return uniWhenCompleteStage(null, action); } - public CompletableFuture whenCompleteAsync - (BiConsumer action) { - return doWhenComplete(action, ForkJoinPool.commonPool()); + public CompletableFuture whenCompleteAsync( + BiConsumer action) { + return uniWhenCompleteStage(asyncPool, action); } - public CompletableFuture whenCompleteAsync - (BiConsumer action, - Executor executor) { - if (executor == null) throw new NullPointerException(); - return doWhenComplete(action, executor); + public CompletableFuture whenCompleteAsync( + BiConsumer action, Executor executor) { + return uniWhenCompleteStage(screenExecutor(executor), action); } - public CompletableFuture handle - (BiFunction fn) { - return doHandle(fn, null); + public CompletableFuture handle( + BiFunction fn) { + return uniHandleStage(null, fn); } - public CompletableFuture handleAsync - (BiFunction fn) { - return doHandle(fn, ForkJoinPool.commonPool()); + public CompletableFuture handleAsync( + BiFunction fn) { + return uniHandleStage(asyncPool, fn); } - public CompletableFuture handleAsync - (BiFunction fn, - Executor executor) { - if (executor == null) throw new NullPointerException(); - return doHandle(fn, executor); + public CompletableFuture handleAsync( + BiFunction 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 exceptionally - (Function fn) { - if (fn == null) throw new NullPointerException(); - CompletableFuture dst = new CompletableFuture(); - ExceptionCompletion d = null; - Object r; - if ((r = result) == null) { - CompletionNode p = - new CompletionNode(d = new ExceptionCompletion - (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 exceptionally( + Function 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 allOf(CompletableFuture... cfs) { - int len = cfs.length; // Directly handle empty and singleton cases - if (len > 1) - return allTree(cfs, 0, len - 1); - else { - CompletableFuture dst = new CompletableFuture(); - 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 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 dst = new CompletableFuture(); - 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 anyOf(CompletableFuture... cfs) { - int len = cfs.length; // Same idea as allOf - if (len > 1) - return anyTree(cfs, 0, len - 1); - else { - CompletableFuture dst = new CompletableFuture(); - CompletableFuture f; - if (len == 0) - ; // skip - else if ((f = cfs[0]) == null) - throw new NullPointerException(); - else { - ThenCopy d = null; - CompletionNode p = null; - Object r; - while ((r = f.result) == null) { - if (d == null) - d = new ThenCopy(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 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 dst = new CompletableFuture(); - 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); } } } diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.base/share/classes/java/util/concurrent/CompletionStage.java --- 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 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. + * + *

    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 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. + * + *

    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 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. + * + *

    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. + * + *

    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. + * + *

    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. + * + *

    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 diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java --- 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"); } } diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java --- 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() { + try { + metaInfo = AccessController.doPrivileged(new PrivilegedExceptionAction() { @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 all = createLanguageTagSet("All"); + Set all = createLanguageTagSet("AvailableLocales"); Locale[] locs = new Locale[all.size()]; int index = 0; for (String tag : all) { @@ -102,11 +107,10 @@ @Override protected Set 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 tagset = new HashSet<>(); StringTokenizer tokens = new StringTokenizer(supportedLocaleString); while (tokens.hasMoreTokens()) { diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.base/share/classes/sun/util/locale/provider/AuxLocaleProviderAdapter.java --- 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, LocaleServiceProvider> providersMap = + private final ConcurrentMap, 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() { diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java --- 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> langtagSets = new ConcurrentHashMap<>(); @@ -356,26 +355,56 @@ } protected Set createLanguageTagSet(String category) { - String supportedLocaleString = LocaleDataMetaInfo.getSupportedLocaleString(category); + String supportedLocaleString = createSupportedLocaleString(category); if (supportedLocaleString == null) { return Collections.emptySet(); } Set 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() { + @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() { - @Override - public Boolean run() { - return f.exists(); } - }); - } - } - } - return isNonENSupported; - } -} diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template --- 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 resourceNameToLocales = - new HashMap(7); +public class #Lang#LocaleDataMetaInfo implements LocaleDataMetaInfo { + private static final Map 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); } } diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo.java --- /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); +} diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.base/share/classes/sun/util/resources/LocaleData.java --- 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; diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/macosx/classes/sun/lwawt/LWLightweightFramePeer.java --- 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 diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java --- 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 createDragGestureRecognizer( Class 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: diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ja.properties --- 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 diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ko.properties --- 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 diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_CN.properties --- 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 diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_TW.properties --- 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 diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java --- 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 pa = new PrivilegedAction() { - 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() { public Boolean run() { - return getStandardProfileFile(fileName) != null; + return PCMM.class.getResource("profiles/"+fileName) != null; } }); } diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/javax/imageio/ImageReader.java --- 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 Iterator of * ImageTypeSpecifiers 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 BufferedImage to which decoded pixel diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataNode.java --- 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 null or an * IIOMetadataNode. + * + * @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) { diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/javax/print/attribute/standard/DialogTypeSelection.java --- 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. *

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

    * For class DialogTypeSelection the category name is diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/javax/swing/JSlider.java --- 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 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 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 Dictionary containing labels and * where to draw them */ - public Dictionary 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 labels ) { - Dictionary 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 labelTable = getLabelTable(); + @SuppressWarnings("rawtypes") + Dictionary labelTable = getLabelTable(); if (labelTable == null) { return; } - Enumeration 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 labelTable = getLabelTable(); + @SuppressWarnings("rawtypes") + Dictionary labelTable = getLabelTable(); if (labelTable != null) { - Enumeration 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 keys = getLabelTable().keys(); + Enumeration keys = getLabelTable().keys(); Hashtable 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 labelTable = getLabelTable(); + @SuppressWarnings("rawtypes") + Dictionary labelTable = getLabelTable(); if (labelTable != null && (labelTable instanceof PropertyChangeListener)) { removePropertyChangeListener((PropertyChangeListener) labelTable); diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/javax/swing/JTable.java --- 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> rowData, Vector columnNames) { + @SuppressWarnings("rawtypes") + public JTable(Vector rowData, Vector columnNames) { this(new DefaultTableModel(rowData, columnNames)); } diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSliderUI.java --- 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 dictionary = slider.getLabelTable(); + @SuppressWarnings("rawtypes") + Dictionary dictionary = slider.getLabelTable(); if (dictionary != null) { sameLabelBaselines = true; - Enumeration 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 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 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 dictionary = slider.getLabelTable(); + @SuppressWarnings("rawtypes") + Dictionary dictionary = slider.getLabelTable(); if (dictionary == null) { return null; } - Enumeration 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 dictionary = slider.getLabelTable(); + @SuppressWarnings("rawtypes") + Dictionary dictionary = slider.getLabelTable(); if (dictionary == null) { return null; } - Enumeration 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 dictionary = slider.getLabelTable(); + @SuppressWarnings("rawtypes") + Dictionary dictionary = slider.getLabelTable(); if ( dictionary != null ) { - Enumeration 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) { diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSliderUI.java --- 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 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 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; diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/javax/swing/table/DefaultTableModel.java --- 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 Vector of Vectors of * Object values. */ - protected Vector> dataVector; + @SuppressWarnings("rawtypes") + protected Vector dataVector; /** The Vector of column identifiers. */ - protected Vector 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 (without adding copying of input Vectors), + // would disallow existing code that used, say, a Vector + // as an input parameter. // // Constructors @@ -121,7 +129,7 @@ * @see #setDataVector * @see #setValueAt */ - public DefaultTableModel(Vector columnNames, int rowCount) { + public DefaultTableModel(Vector columnNames, int rowCount) { setDataVector(newVector(rowCount), columnNames); } @@ -156,7 +164,8 @@ * @see #getDataVector * @see #setDataVector */ - public DefaultTableModel(Vector> data, Vector columnNames) { + @SuppressWarnings("rawtypes") + public DefaultTableModel(Vector data, Vector columnNames) { setDataVector(data, columnNames); } @@ -191,7 +200,8 @@ * @see #newRowsAdded * @see #setDataVector */ - public Vector> getDataVector() { + @SuppressWarnings("rawtypes") + public Vector getDataVector() { return dataVector; } @@ -219,9 +229,10 @@ * @param columnIdentifiers the names of the columns * @see #getDataVector */ - public void setDataVector(Vector> dataVector, - Vector columnIdentifiers) { - this.dataVector = nonNullVector(dataVector); + @SuppressWarnings({"rawtypes", "unchecked"}) + public void setDataVector(Vector dataVector, + Vector columnIdentifiers) { + this.dataVector = nonNullVector((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 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 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 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 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 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 rowVector = dataVector.elementAt(row); rowVector.setElementAt(aValue, column); fireTableCellUpdated(row, column); diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/javax/swing/tree/DefaultMutableTreeNode.java --- 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 { - private final Stack> stack = new Stack<>(); + private final Stack> stack = new Stack<>(); public PreorderEnumeration(TreeNode rootNode) { super(); @@ -1331,10 +1331,9 @@ } public TreeNode nextElement() { - Enumeration enumer = stack.peek(); + Enumeration enumer = stack.peek(); TreeNode node = enumer.nextElement(); - @SuppressWarnings("unchecked") - Enumeration children = node.children(); + Enumeration children = node.children(); if (!enumer.hasMoreElements()) { stack.pop(); @@ -1351,7 +1350,7 @@ final class PostorderEnumeration implements Enumeration { protected TreeNode root; - protected Enumeration children; + protected Enumeration children; protected Enumeration subtree; public PostorderEnumeration(TreeNode rootNode) { diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/javax/swing/tree/TreeNode.java --- 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 children(); + Enumeration children(); } diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/sun/awt/LightweightFrame.java --- 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 createDragGestureRecognizer( + Class 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); } diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java --- 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 diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java --- 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); diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/sun/java2d/cmm/profiles/CIEXYZ.pf Binary file jdk/src/java.desktop/share/classes/sun/java2d/cmm/profiles/CIEXYZ.pf has changed diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/sun/java2d/cmm/profiles/GRAY.pf Binary file jdk/src/java.desktop/share/classes/sun/java2d/cmm/profiles/GRAY.pf has changed diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/sun/java2d/cmm/profiles/LINEAR_RGB.pf Binary file jdk/src/java.desktop/share/classes/sun/java2d/cmm/profiles/LINEAR_RGB.pf has changed diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/sun/java2d/cmm/profiles/PYCC.pf Binary file jdk/src/java.desktop/share/classes/sun/java2d/cmm/profiles/PYCC.pf has changed diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/sun/java2d/cmm/profiles/sRGB.pf Binary file jdk/src/java.desktop/share/classes/sun/java2d/cmm/profiles/sRGB.pf has changed diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java --- 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 createDragGestureRecognizer( + Class 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); + } } diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/classes/sun/swing/LightweightContent.java --- 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 createDragGestureRecognizer( + Class 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) {} } diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/conf/cmm/lcms/CIEXYZ.pf Binary file jdk/src/java.desktop/share/conf/cmm/lcms/CIEXYZ.pf has changed diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/conf/cmm/lcms/GRAY.pf Binary file jdk/src/java.desktop/share/conf/cmm/lcms/GRAY.pf has changed diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/conf/cmm/lcms/LINEAR_RGB.pf Binary file jdk/src/java.desktop/share/conf/cmm/lcms/LINEAR_RGB.pf has changed diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/conf/cmm/lcms/PYCC.pf Binary file jdk/src/java.desktop/share/conf/cmm/lcms/PYCC.pf has changed diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/share/conf/cmm/lcms/sRGB.pf Binary file jdk/src/java.desktop/share/conf/cmm/lcms/sRGB.pf has changed diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/unix/classes/sun/awt/X11/XLightweightFramePeer.java --- 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); + } } diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java --- 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 diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/unix/native/common/sun/awt/CUPSfuncs.c --- 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); } diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/unix/native/common/sun/awt/X11Color.c --- 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); diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/unix/native/common/sun/awt/awt.h --- 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) diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/unix/native/libawt_xawt/sun/awt/awt_GraphicsEnv.c --- 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 */ diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/unix/native/libawt_xawt/sun/awt/sun_awt_X11_GtkFileDialogPeer.c --- 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; + } } } diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/windows/classes/sun/awt/windows/WLightweightFramePeer.java --- 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); + } } diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java --- 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 diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/windows/native/libawt/sun/windows/WPrinterJob.cpp --- 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 { diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/windows/native/libawt/sun/windows/awt_InputMethod.cpp --- 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; } } diff -r bbce32388a2d -r b764fbee45e2 jdk/src/java.desktop/windows/native/libawt/sun/windows/awt_Win32GraphicsDevice.cpp --- 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); diff -r bbce32388a2d -r b764fbee45e2 jdk/src/jdk.jconsole/share/classes/sun/tools/jconsole/inspector/TableSorter.java --- 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 getRow(int row) { + private Vector getRow(int row) { return dataVector.elementAt(row); } @SuppressWarnings("unchecked") - private void setRow(Vector data, int row) { + private void setRow(Vector data, int row) { dataVector.setElementAt(data,row); } private void swap(int i, int j, int column) { - Vector data = getRow(i); + Vector data = getRow(i); setRow(getRow(j),i); setRow(data,j); diff -r bbce32388a2d -r b764fbee45e2 jdk/src/jdk.localedata/META-INF/cldrdata-services/sun.util.locale.provider.LocaleDataMetaInfo --- /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 diff -r bbce32388a2d -r b764fbee45e2 jdk/src/jdk.localedata/META-INF/localedata-services/sun.util.locale.provider.LocaleDataMetaInfo --- /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 diff -r bbce32388a2d -r b764fbee45e2 jdk/src/jdk.localedata/share/classes/sun/util/resources/lt/CurrencyNames_lt_LT.properties --- 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 diff -r bbce32388a2d -r b764fbee45e2 jdk/test/java/awt/Frame/MiscUndecorated/ActiveAWTWindowTest.java --- /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"); + } + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/java/awt/Frame/MiscUndecorated/ActiveSwingWindowTest.java --- /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"); + } + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/java/awt/Frame/MiscUndecorated/FrameCloseTest.java --- /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"); + } + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/java/awt/Frame/MiscUndecorated/RepaintTest.java --- /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; + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/java/awt/Frame/MiscUndecorated/UndecoratedInitiallyIconified.java --- /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"); + } + }); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/java/awt/Mixing/AWT_Mixing/Util.java --- 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; - -/** - *

    This class contains utilities useful for regression testing. - *

    When using jtreg you would include this class into the build - * list via something like: - *

    -     &library ../../../../share/lib/AWT_Mixing/src/regtesthelpers/
    -     &build Util
    -     &run main YourTest
    -   
    - * 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. - *

    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() { - 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); - - } -} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/java/awt/color/LoadStandardProfilesTest.java --- /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); + } + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/java/security/AccessController/DoPrivAccomplice.java --- /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; + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/java/security/AccessController/DoPrivAccompliceTest.java --- /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 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"); + } + } + +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/java/security/AccessController/DoPrivTest.java --- /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); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/java/security/KeyStore/TestKeyStoreBasic.java --- /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"); + + } + } + } + +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/java/security/KeyStore/TestKeyStoreEntry.java --- /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"); + } + } + } + } + +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/java/sql/test/sql/DriverManagerPermissionsTests.java --- /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()); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/java/sql/util/BaseTest.java --- 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); + } } diff -r bbce32388a2d -r b764fbee45e2 jdk/test/java/sql/util/TestPolicy.java --- /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("<>", + "read, write, delete")); + } + + /* + * Overloaded methods from the Policy class + */ + @Override + public String toString() { + StringJoiner sj = new StringJoiner("\n", "policy: ", ""); + Enumeration 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); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/java/util/Currency/tablea1.txt --- 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 diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/net/ssl/TLS/CipherTestUtils.java --- /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 TESTS = new ArrayList<>(3); + private static final List 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); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/net/ssl/TLS/JSSEClient.java --- /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(); + } + } + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/net/ssl/TLS/JSSEServer.java --- /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); + } + } + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/net/ssl/TLS/TestJSSE.java --- /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); + } + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/sql/testng/test/rowset/spi/SyncFactoryPermissionsTests.java --- /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); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/sql/testng/util/BaseTest.java --- 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); + } } diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/sql/testng/util/TestPolicy.java --- /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("<>", + "read, write, delete")); + } + + /* + * Overloaded methods from the Policy class + */ + @Override + public String toString() { + StringJoiner sj = new StringJoiner("\n", "policy: ", ""); + Enumeration 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); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/BaseTest.java --- /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); + } + } + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/BasicTest.java --- /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()); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/FixedAttrTest.java --- /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()); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/IdIdrefCheckingTest.java --- /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()); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/IdentityConstraintCheckingTest.java --- /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()); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/IgnoreXSITypeTest_A_A.java --- /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()); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/IgnoreXSITypeTest_A_C.java --- /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()); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/IgnoreXSITypeTest_C_A.java --- /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()); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/IgnoreXSITypeTest_C_AC.java --- /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()); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/IgnoreXSITypeTest_C_C.java --- /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()); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/IgnoreXSITypeTest_C_CA.java --- /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()); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/RootTypeDefinitionTest.java --- /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()); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/SpecialCaseErrorHandler.java --- /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 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(); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/TEST.properties --- /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 = . diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/UnparsedEntityCheckingTest.java --- /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()); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/UseGrammarPoolOnlyTest_False.java --- /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()); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/UseGrammarPoolOnlyTest_True.java --- /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()); + } +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/base.xml --- /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 @@ + + + diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/base.xsd --- /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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/fixedAttr.xml --- /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 @@ + + + howdy + hey + diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/idIdref.xml --- /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 @@ + + + + + + diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/idc.xml --- /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 @@ + + + 1 + 2 + 2 + 3 + diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/idc.xsd --- /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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/otherNamespace.xml --- /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 @@ + + + diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/otherNamespace.xsd --- /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 @@ + + + + + + + + + + + + + + + diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/unparsedEntity.dtd --- /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 @@ + + + diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/unparsedEntity.xml --- /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 @@ + + + + diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/xsitype_A_A.xml --- /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 @@ + + + + diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/xsitype_A_C.xml --- /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 @@ + + + + diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/xsitype_C_A.xml --- /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 @@ + + + + diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/xsitype_C_AC.xml --- /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 @@ + + + + + diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/xsitype_C_C.xml --- /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 @@ + + + + diff -r bbce32388a2d -r b764fbee45e2 jdk/test/javax/xml/jaxp/testng/validation/8037819/xsitype_C_CA.xml --- /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 @@ + + + + + diff -r bbce32388a2d -r b764fbee45e2 jdk/test/lib/testlibrary/JavaToolUtils.java --- /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 files) throws IOException { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + try (StandardJavaFileManager fileManager = compiler. + getStandardFileManager(null, null, null)) { + Iterable 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 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 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 commands) throws Exception { + return runJava(commands, DEFAULT_WAIT_TIME); + } + + /** + * Run any command + * @param commands + * @return + * @throws Exception + */ + public static int runCommand(List 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; + } + + +} diff -r bbce32388a2d -r b764fbee45e2 jdk/test/sun/management/jmxremote/startstop/JMXStartStopTest.java --- 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); } }, diff -r bbce32388a2d -r b764fbee45e2 jdk/test/sun/text/resources/LocaleData --- 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 diff -r bbce32388a2d -r b764fbee45e2 jdk/test/sun/text/resources/LocaleDataTest.java --- 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 * */ diff -r bbce32388a2d -r b764fbee45e2 jdk/test/sun/tools/jstatd/JstatdTest.java --- 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 { diff -r bbce32388a2d -r b764fbee45e2 jdk/test/sun/util/locale/provider/Bug8038436.java --- /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 gotList = Arrays.asList(got).stream() + .map(Locale::toLanguageTag) + .sorted() + .map(Locale::forLanguageTag) + .collect(Collectors.toList()); + List 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()); + } + } +} diff -r bbce32388a2d -r b764fbee45e2 make/CompileJavaModules.gmk --- 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 += \ diff -r bbce32388a2d -r b764fbee45e2 make/Main.gmk --- 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 diff -r bbce32388a2d -r b764fbee45e2 make/common/MakeBase.gmk --- 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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/.hgtags --- 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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/bin/dump_octane_code.sh --- 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" diff -r bbce32388a2d -r b764fbee45e2 nashorn/bin/fixorphantests.sh --- 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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/bin/fixwhitespace.sh --- 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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/bin/jjsdebug.sh --- 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 $* diff -r bbce32388a2d -r b764fbee45e2 nashorn/bin/rm-non-tracked.sh --- 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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/bin/run_octane.sh --- 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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/bin/rundiff.sh --- 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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/bin/runopt.sh --- 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 - diff -r bbce32388a2d -r b764fbee45e2 nashorn/bin/runopt_noassert.sh --- 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 \ diff -r bbce32388a2d -r b764fbee45e2 nashorn/bin/runopt_nojfr.sh --- 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 \ diff -r bbce32388a2d -r b764fbee45e2 nashorn/make/build.xml --- 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"; }; diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java --- 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 implements Loggable { +final class AssignSymbols extends NodeVisitor 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(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 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 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 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); + } } diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java --- 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(); diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java --- 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 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 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 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) { diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/DumpBytecode.java --- 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); diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java --- 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> 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 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 tuple) { method.dup(); diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MapCreator.java --- 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 structure, final List> 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; } } diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java --- 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) { diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java --- 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. + *

    + * 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() { @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() { + @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 filesStream = Files.walk(baseCacheDir.toPath())) { + // TODO: rewrite below once we can use JDK8 syntactic constructs + return filesStream + .filter(new Predicate() { + @Override + public boolean test(final Path path) { + return !Files.isDirectory(path); + }; + }) + .map(new Function() { + @Override + public PathAndTime apply(final Path path) { + return new PathAndTime(path); + } + }) + .sorted() + .map(new Function() { + @Override + public Path apply(final PathAndTime pathAndTime) { + return pathAndTime.path; + } + }) + .toArray(new IntFunction() { // Replace with Path::new + @Override + public Path[] apply(final int length) { + return new Path[length]; + } + }); + } + } + + private static class PathAndTime implements Comparable { + 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)); + } } diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java --- 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; } diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/Type.java --- 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 readTypeMap(final DataInput input) throws IOException { final int size = input.readInt(); - if (size == 0) { + if (size <= 0) { return null; } final Map 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); } diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java --- 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 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 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); } /** diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java --- 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__). * diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Symbol.java --- 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. diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/VarNode.java --- 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) { diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java --- 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 variableStatement(final boolean isStatement) { + private List variableStatement(final TokenType varType, final boolean isStatement) { // VAR tested in caller. next(); final List 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); diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java --- 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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java --- 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 { diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java --- 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) diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java --- 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); } diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/OptimisticReturnFilters.java --- 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); diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java --- 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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java --- 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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java --- 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"); diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java --- 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) { diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java --- 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); } diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java --- 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. diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java --- 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; diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java --- 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; } } diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java --- 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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties --- 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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Options.properties --- 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, \ diff -r bbce32388a2d -r b764fbee45e2 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java --- 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(); diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/JDK-8056129.js --- /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) diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/JDK-8056129.js.EXPECTED --- /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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/JDK-8057019-2.js --- /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'); + diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/JDK-8057019-2.js.EXPECTED --- /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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/JDK-8057019-payload.js --- /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); +} diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/JDK-8057019.js --- /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'); + diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/JDK-8057019.js.EXPECTED --- /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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/apply_to_call/apply_to_call4.js.EXPECTED --- 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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/compile-octane-normal.js --- 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); diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/compile-octane-splitter.js --- 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); diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/compile-octane.js --- 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."); diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/block-function-decl.js --- /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); +} + diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/block-function-decl.js.EXPECTED --- /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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/const-empty.js --- /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); +} diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/const-empty.js.EXPECTED --- /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@1:2:7 Missing assignment to constant "x" +const x; + ^ diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/const-reassign.js --- /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); +} diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/const-reassign.js.EXPECTED --- /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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/const-redeclare.js --- /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); +} diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/const-redeclare.js.EXPECTED --- /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@1:2:6 Variable "x" has already been declared +const x = 2; + ^ diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/const-self.js --- /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); +} diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/const-self.js.EXPECTED --- /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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/const-tdz.js --- /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); + } +} + diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/const-tdz.js.EXPECTED --- /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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/const.js --- /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(); diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/const.js.EXPECTED --- /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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/for-let.js --- /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); +} diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/for-let.js.EXPECTED --- /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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/let-eval.js --- /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); diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/let-eval.js.EXPECTED --- /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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/let-load-lib.js --- /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(); +} diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/let-load.js --- /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); +} + + diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/let-load.js.EXPECTED --- /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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/let-nodeclare.js --- /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); +} diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/let-nodeclare.js.EXPECTED --- /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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/let-redeclare.js --- /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); +} diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/let-redeclare.js.EXPECTED --- /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@1:2:4 Variable "x" has already been declared +let x = 2; + ^ diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/let-self.js --- /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); +} diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/let-self.js.EXPECTED --- /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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/let-tdz.js --- /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); + } +} + diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/let-tdz.js.EXPECTED --- /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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/let.js --- /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(); + diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/basic/es6/let.js.EXPECTED --- /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 diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/script/trusted/JDK-8006529.js --- 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); }; diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java --- 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); diff -r bbce32388a2d -r b764fbee45e2 nashorn/test/src/jdk/nashorn/internal/parser/ParserTest.java --- 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);