# HG changeset patch # User duke # Date 1499266783 -7200 # Node ID e17115919cc749b44b80a3ef6adf1e0ae7c27474 # Parent ae9b655e7393615b307c09431ed5b6ce34f4c8bf# Parent 22129b902bf63c934a8f3b1171db3f7263ae485d Merge diff -r ae9b655e7393 -r e17115919cc7 .hgtags-top-repo --- a/.hgtags-top-repo Tue Sep 01 23:44:41 2009 +0100 +++ b/.hgtags-top-repo Wed Jul 05 16:59:43 2017 +0200 @@ -44,3 +44,4 @@ c4523c6f82048f420bf0d57c4cd47976753b7d2c jdk7-b67 e1b972ff53cd58f825791f8ed9b2deffd16e768c jdk7-b68 82e6c820c51ac27882b77755d42efefdbf1dcda0 jdk7-b69 +175cb3fe615998d1004c6d3fd96e6d2e86b6772d jdk7-b70 diff -r ae9b655e7393 -r e17115919cc7 hotspot/.hgtags --- a/hotspot/.hgtags Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/.hgtags Wed Jul 05 16:59:43 2017 +0200 @@ -44,3 +44,4 @@ 18f526145aea355a9320b724373386fc2170f183 jdk7-b67 d07e68298d4e17ebf93d8299e43fcc3ded26472a jdk7-b68 54fd4d9232969ea6cd3d236e5ad276183bb0d423 jdk7-b69 +0632c3e615a315ff11e2ab1d64f4d82ff9853461 jdk7-b70 diff -r ae9b655e7393 -r e17115919cc7 hotspot/agent/make/saenv.sh --- a/hotspot/agent/make/saenv.sh Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/agent/make/saenv.sh Wed Jul 05 16:59:43 2017 +0200 @@ -48,6 +48,8 @@ CPU=i386 fi else + LD_AUDIT_32=$STARTDIR/../src/os/solaris/proc/`uname -p`/libsaproc_audit.so + export LD_AUDIT_32 SA_LIBPATH=$STARTDIR/../src/os/solaris/proc/`uname -p`:$STARTDIR/solaris/`uname -p` OPTIONS="-Dsa.library.path=$SA_LIBPATH -Dsun.jvm.hotspot.debugger.useProcDebugger" CPU=sparc diff -r ae9b655e7393 -r e17115919cc7 hotspot/agent/make/saenv64.sh --- a/hotspot/agent/make/saenv64.sh Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/agent/make/saenv64.sh Wed Jul 05 16:59:43 2017 +0200 @@ -43,6 +43,8 @@ fi fi +LD_AUDIT_64=$STARTDIR/../src/os/solaris/proc/$CPU/libsaproc_audit.so +export LD_AUDIT_64 SA_LIBPATH=$STARTDIR/../src/os/solaris/proc/$CPU:$STARTDIR/solaris/$CPU OPTIONS="-Dsa.library.path=$SA_LIBPATH -Dsun.jvm.hotspot.debugger.useProcDebugger" diff -r ae9b655e7393 -r e17115919cc7 hotspot/agent/src/os/solaris/proc/Makefile --- a/hotspot/agent/src/os/solaris/proc/Makefile Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/agent/src/os/solaris/proc/Makefile Wed Jul 05 16:59:43 2017 +0200 @@ -56,24 +56,28 @@ @javah -classpath $(CLASSES_DIR) -jni sun.jvm.hotspot.debugger.proc.ProcDebuggerLocal CC -G -KPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/solaris saproc.cpp \ -M mapfile -o $@/libsaproc.so -ldemangle + CC -o $@/libsaproc_audit.so -G -Kpic -z defs saproc_audit.cpp -lmapmalloc -ldl -lc amd64:: javahomecheck $(MKDIRS) $@ @javah -classpath $(CLASSES_DIR) -jni sun.jvm.hotspot.debugger.proc.ProcDebuggerLocal CC -G -KPIC -xarch=amd64 -I${JAVA_HOME}/include -I${JAVA_HOME}/include/solaris saproc.cpp \ -M mapfile -o $@/libsaproc.so -ldemangle + CC -xarch=amd64 -o $@/libsaproc_audit.so -G -Kpic -z defs saproc_audit.cpp -lmapmalloc -ldl -lc sparc:: javahomecheck $(MKDIRS) $@ @javah -classpath $(CLASSES_DIR) -jni sun.jvm.hotspot.debugger.proc.ProcDebuggerLocal CC -G -KPIC -xarch=v8 -I${JAVA_HOME}/include -I${JAVA_HOME}/include/solaris saproc.cpp \ -M mapfile -o $@/libsaproc.so -ldemangle + CC -xarch=v8 -o $@/libsaproc_audit.so -G -Kpic -z defs saproc_audit.cpp -lmapmalloc -ldl -lc sparcv9:: javahomecheck $(MKDIRS) $@ @javah -classpath $(CLASSES_DIR) -jni sun.jvm.hotspot.debugger.proc.ProcDebuggerLocal CC -G -KPIC -xarch=v9 -I${JAVA_HOME}/include -I${JAVA_HOME}/include/solaris saproc.cpp \ -M mapfile -o $@/libsaproc.so -ldemangle + CC -xarch=v9 -o $@/libsaproc_audit.so -G -Kpic -z defs saproc_audit.cpp -lmapmalloc -ldl -lc clean:: $(RM) -rf sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal.h diff -r ae9b655e7393 -r e17115919cc7 hotspot/agent/src/os/solaris/proc/mapfile --- a/hotspot/agent/src/os/solaris/proc/mapfile Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/agent/src/os/solaris/proc/mapfile Wed Jul 05 16:59:43 2017 +0200 @@ -45,6 +45,8 @@ Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_resume0; Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_suspend0; Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_writeBytesToProcess0; + # this is needed by saproc_audit.c to redirect opens in libproc.so + libsaproc_open; local: *; }; diff -r ae9b655e7393 -r e17115919cc7 hotspot/agent/src/os/solaris/proc/saproc.cpp --- a/hotspot/agent/src/os/solaris/proc/saproc.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/agent/src/os/solaris/proc/saproc.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -214,49 +214,58 @@ } } -static int find_file_hook(const char * name, int elf_checksum) { - init_alt_root(); - - if (_libsaproc_debug) { - printf("libsaproc DEBUG: find_file_hook %s 0x%x\n", name, elf_checksum); - } +// This function is a complete substitute for the open system call +// since it's also used to override open calls from libproc to +// implement as a pathmap style facility for the SA. If libproc +// starts using other interfaces then this might have to extended to +// cover other calls. +extern "C" int libsaproc_open(const char * name, int oflag, ...) { + if (oflag == O_RDONLY) { + init_alt_root(); - if (alt_root_len > 0) { - int fd = -1; - char alt_path[PATH_MAX+1]; - - strcpy(alt_path, alt_root); - strcat(alt_path, name); - fd = open(alt_path, O_RDONLY); - if (fd >= 0) { - if (_libsaproc_debug) { - printf("libsaproc DEBUG: find_file_hook substituted %s\n", alt_path); - } - return fd; + if (_libsaproc_debug) { + printf("libsaproc DEBUG: libsaproc_open %s\n", name); } - if (strrchr(name, '/')) { + if (alt_root_len > 0) { + int fd = -1; + char alt_path[PATH_MAX+1]; + strcpy(alt_path, alt_root); - strcat(alt_path, strrchr(name, '/')); + strcat(alt_path, name); fd = open(alt_path, O_RDONLY); if (fd >= 0) { if (_libsaproc_debug) { - printf("libsaproc DEBUG: find_file_hook substituted %s\n", alt_path); + printf("libsaproc DEBUG: libsaproc_open substituted %s\n", alt_path); } return fd; } + + if (strrchr(name, '/')) { + strcpy(alt_path, alt_root); + strcat(alt_path, strrchr(name, '/')); + fd = open(alt_path, O_RDONLY); + if (fd >= 0) { + if (_libsaproc_debug) { + printf("libsaproc DEBUG: libsaproc_open substituted %s\n", alt_path); + } + return fd; + } + } } } - return -1; + + { + mode_t mode; + va_list ap; + va_start(ap, oflag); + mode = va_arg(ap, mode_t); + va_end(ap); + + return open(name, oflag, mode); + } } -static int pathmap_open(const char* name) { - int fd = open(name, O_RDONLY); - if (fd < 0) { - fd = find_file_hook(name, 0); - } - return fd; -} static void * pathmap_dlopen(const char * name, int mode) { init_alt_root(); @@ -608,7 +617,7 @@ print_debug("looking for %s\n", classes_jsa); // open the classes[_g].jsa - int fd = pathmap_open(classes_jsa); + int fd = libsaproc_open(classes_jsa, O_RDONLY); if (fd < 0) { char errMsg[ERR_MSG_SIZE]; sprintf(errMsg, "can't open shared archive file %s", classes_jsa); @@ -1209,8 +1218,6 @@ return res; } -typedef int (*find_file_hook_t)(const char *, int elf_checksum); - /* * Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal * Method: initIDs @@ -1230,16 +1237,6 @@ if (libproc_handle == 0) THROW_NEW_DEBUGGER_EXCEPTION("can't load libproc.so, if you are using Solaris 5.7 or below, copy libproc.so from 5.8!"); - // If possible, set shared object find file hook. - void (*set_hook)(find_file_hook_t) = (void(*)(find_file_hook_t))dlsym(libproc_handle, "Pset_find_file_hook"); - if (set_hook) { - // we found find file hook symbol, set up our hook function. - set_hook(find_file_hook); - } else if (getenv(SA_ALTROOT)) { - printf("libsaproc WARNING: %s set, but can't set file hook. " \ - "Did you use right version of libproc.so?\n", SA_ALTROOT); - } - p_ps_prochandle_ID = env->GetFieldID(clazz, "p_ps_prochandle", "J"); CHECK_EXCEPTION; diff -r ae9b655e7393 -r e17115919cc7 hotspot/agent/src/os/solaris/proc/saproc_audit.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/agent/src/os/solaris/proc/saproc_audit.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,98 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// This class sets up an interposer on open calls from libproc.so to +// support a pathmap facility in the SA. + +static uintptr_t* libproc_cookie; +static uintptr_t* libc_cookie; +static uintptr_t* libsaproc_cookie; + + +uint_t +la_version(uint_t version) +{ + return (LAV_CURRENT); +} + + +uint_t +la_objopen(Link_map * lmp, Lmid_t lmid, uintptr_t * cookie) +{ + if (strstr(lmp->l_name, "/libproc.so") != NULL) { + libproc_cookie = cookie; + return LA_FLG_BINDFROM; + } + if (strstr(lmp->l_name, "/libc.so") != NULL) { + libc_cookie = cookie; + return LA_FLG_BINDTO; + } + if (strstr(lmp->l_name, "/libsaproc.so") != NULL) { + libsaproc_cookie = cookie; + return LA_FLG_BINDTO | LA_FLG_BINDFROM; + } + return 0; +} + + +#if defined(_LP64) +uintptr_t +la_symbind64(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcook, + uintptr_t *defcook, uint_t *sb_flags, const char *sym_name) +#else +uintptr_t +la_symbind32(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcook, + uintptr_t *defcook, uint_t *sb_flags) +#endif +{ +#if !defined(_LP64) + const char *sym_name = (const char *)symp->st_name; +#endif + if (strcmp(sym_name, "open") == 0 && refcook == libproc_cookie) { + // redirect all open calls from libproc.so through libsaproc_open which will + // try the alternate library locations first. + void* handle = dlmopen(LM_ID_BASE, "libsaproc.so", RTLD_NOLOAD); + if (handle == NULL) { + fprintf(stderr, "libsaproc_audit.so: didn't find libsaproc.so during linking\n"); + } else { + uintptr_t libsaproc_open = (uintptr_t)dlsym(handle, "libsaproc_open"); + if (libsaproc_open == 0) { + fprintf(stderr, "libsaproc_audit.so: didn't find libsaproc_open during linking\n"); + } else { + return libsaproc_open; + } + } + } + return symp->st_value; +} diff -r ae9b655e7393 -r e17115919cc7 hotspot/agent/src/share/classes/sun/jvm/hotspot/code/DebugInfoReadStream.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/DebugInfoReadStream.java Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/DebugInfoReadStream.java Wed Jul 05 16:59:43 2017 +0200 @@ -81,8 +81,4 @@ Assert.that(false, "should not reach here"); return null; } - - public int readBCI() { - return readInt() + InvocationEntryBCI; - } } diff -r ae9b655e7393 -r e17115919cc7 hotspot/agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java Wed Jul 05 16:59:43 2017 +0200 @@ -82,6 +82,7 @@ tty.print(" "); sd.getMethod().printValueOn(tty); tty.print(" @" + sd.getBCI()); + tty.print(" reexecute=" + sd.getReexecute()); tty.println(); } } diff -r ae9b655e7393 -r e17115919cc7 hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ScopeDesc.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ScopeDesc.java Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ScopeDesc.java Wed Jul 05 16:59:43 2017 +0200 @@ -41,6 +41,7 @@ private NMethod code; private Method method; private int bci; + private boolean reexecute; /** Decoding offsets */ private int decodeOffset; private int senderDecodeOffset; @@ -61,7 +62,7 @@ senderDecodeOffset = stream.readInt(); method = (Method) VM.getVM().getObjectHeap().newOop(stream.readOopHandle()); - bci = stream.readBCI(); + setBCIAndReexecute(stream.readInt()); // Decode offsets for body and sender localsDecodeOffset = stream.readInt(); expressionsDecodeOffset = stream.readInt(); @@ -78,7 +79,7 @@ senderDecodeOffset = stream.readInt(); method = (Method) VM.getVM().getObjectHeap().newOop(stream.readOopHandle()); - bci = stream.readBCI(); + setBCIAndReexecute(stream.readInt()); // Decode offsets for body and sender localsDecodeOffset = stream.readInt(); expressionsDecodeOffset = stream.readInt(); @@ -88,6 +89,7 @@ public NMethod getNMethod() { return code; } public Method getMethod() { return method; } public int getBCI() { return bci; } + public boolean getReexecute() {return reexecute;} /** Returns a List<ScopeValue> */ public List getLocals() { @@ -150,6 +152,7 @@ tty.print("ScopeDesc for "); method.printValueOn(tty); tty.println(" @bci " + bci); + tty.println(" reexecute: " + reexecute); } // FIXME: add more accessors @@ -157,6 +160,11 @@ //-------------------------------------------------------------------------------- // Internals only below this point // + private void setBCIAndReexecute(int combination) { + int InvocationEntryBci = VM.getVM().getInvocationEntryBCI(); + bci = (combination >> 1) + InvocationEntryBci; + reexecute = (combination & 1)==1 ? true : false; + } private DebugInfoReadStream streamAt(int decodeOffset) { return new DebugInfoReadStream(code, decodeOffset, objects); diff -r ae9b655e7393 -r e17115919cc7 hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java Wed Jul 05 16:59:43 2017 +0200 @@ -176,19 +176,6 @@ for (; cur.lessThan(limit);) { Address klassOop = cur.getAddressAt(addressSize); - // FIXME: need to do a better job here. - // can I use bitMap here? - if (klassOop == null) { - //Find the object size using Printezis bits and skip over - System.err.println("Finding object size using Printezis bits and skipping over..."); - long size = collector().blockSizeUsingPrintezisBits(cur); - if (size == -1) { - System.err.println("Printezis bits not set..."); - break; - } - cur = cur.addOffsetTo(adjustObjectSizeInBytes(size)); - } - if (FreeChunk.indicatesFreeChunk(cur)) { if (! cur.equals(regionStart)) { res.add(new MemRegion(regionStart, cur)); @@ -200,12 +187,21 @@ } // note that fc.size() gives chunk size in heap words cur = cur.addOffsetTo(chunkSize * addressSize); - System.err.println("Free chunk in CMS heap, size="+chunkSize * addressSize); regionStart = cur; } else if (klassOop != null) { Oop obj = heap.newOop(cur.addOffsetToAsOopHandle(0)); long objectSize = obj.getObjectSize(); cur = cur.addOffsetTo(adjustObjectSizeInBytes(objectSize)); + } else { + // FIXME: need to do a better job here. + // can I use bitMap here? + //Find the object size using Printezis bits and skip over + long size = collector().blockSizeUsingPrintezisBits(cur); + if (size == -1) { + System.err.println("Printezis bits not set..."); + break; + } + cur = cur.addOffsetTo(adjustObjectSizeInBytes(size)); } } return res; diff -r ae9b655e7393 -r e17115919cc7 hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/FreeChunk.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/FreeChunk.java Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/FreeChunk.java Wed Jul 05 16:59:43 2017 +0200 @@ -63,7 +63,7 @@ public long size() { if (VM.getVM().isCompressedOopsEnabled()) { - Mark mark = new Mark(sizeField.getValue(addr)); + Mark mark = new Mark(addr.addOffsetTo(sizeField.getOffset())); return mark.getSize(); } else { Address size = sizeField.getValue(addr); @@ -83,7 +83,7 @@ public boolean isFree() { if (VM.getVM().isCompressedOopsEnabled()) { - Mark mark = new Mark(sizeField.getValue(addr)); + Mark mark = new Mark(addr.addOffsetTo(sizeField.getOffset())); return mark.isCmsFreeChunk(); } else { Address prev = prevField.getValue(addr); diff -r ae9b655e7393 -r e17115919cc7 hotspot/make/hotspot_version --- a/hotspot/make/hotspot_version Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/make/hotspot_version Wed Jul 05 16:59:43 2017 +0200 @@ -35,7 +35,7 @@ HS_MAJOR_VER=16 HS_MINOR_VER=0 -HS_BUILD_NUMBER=07 +HS_BUILD_NUMBER=08 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 diff -r ae9b655e7393 -r e17115919cc7 hotspot/make/jprt.properties --- a/hotspot/make/jprt.properties Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/make/jprt.properties Wed Jul 05 16:59:43 2017 +0200 @@ -306,7 +306,6 @@ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_ParallelGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_ParNewGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_CMS, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_G1, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCBasher_ParOldGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_default, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_SerialGC, \ diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/cpu/x86/vm/assembler_x86.cpp --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -8335,15 +8335,13 @@ // Cannot assert, unverified entry point counts instructions (see .ad file) // vtableStubs also counts instructions in pd_code_size_limit. // Also do not verify_oop as this is called by verify_oop. - if (Universe::narrow_oop_base() == NULL) { - if (Universe::narrow_oop_shift() != 0) { - assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); - shlq(r, LogMinObjAlignmentInBytes); - } + if (Universe::narrow_oop_shift() != 0) { + assert (Address::times_8 == LogMinObjAlignmentInBytes && + Address::times_8 == Universe::narrow_oop_shift(), "decode alg wrong"); + // Don't use Shift since it modifies flags. + leaq(r, Address(r12_heapbase, r, Address::times_8, 0)); } else { - assert (Address::times_8 == LogMinObjAlignmentInBytes && - Address::times_8 == Universe::narrow_oop_shift(), "decode alg wrong"); - leaq(r, Address(r12_heapbase, r, Address::times_8, 0)); + assert (Universe::narrow_oop_base() == NULL, "sanity"); } } @@ -8358,6 +8356,7 @@ Address::times_8 == Universe::narrow_oop_shift(), "decode alg wrong"); leaq(dst, Address(r12_heapbase, src, Address::times_8, 0)); } else if (dst != src) { + assert (Universe::narrow_oop_base() == NULL, "sanity"); movq(dst, src); } } diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/os/solaris/vm/os_solaris.cpp --- a/hotspot/src/os/solaris/vm/os_solaris.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -1643,7 +1643,8 @@ inline hrtime_t getTimeNanos() { if (VM_Version::supports_cx8()) { const hrtime_t now = gethrtime(); - const hrtime_t prev = max_hrtime; + // Use atomic long load since 32-bit x86 uses 2 registers to keep long. + const hrtime_t prev = Atomic::load((volatile jlong*)&max_hrtime); if (now <= prev) return prev; // same or retrograde time; const hrtime_t obsv = Atomic::cmpxchg(now, (volatile jlong*)&max_hrtime, prev); assert(obsv >= prev, "invariant"); // Monotonicity diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/os/windows/vm/os_windows.cpp --- a/hotspot/src/os/windows/vm/os_windows.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/os/windows/vm/os_windows.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -616,12 +616,13 @@ } julong os::win32::available_memory() { - // FIXME: GlobalMemoryStatus() may return incorrect value if total memory - // is larger than 4GB - MEMORYSTATUS ms; - GlobalMemoryStatus(&ms); - - return (julong)ms.dwAvailPhys; + // Use GlobalMemoryStatusEx() because GlobalMemoryStatus() may return incorrect + // value if total memory is larger than 4GB + MEMORYSTATUSEX ms; + ms.dwLength = sizeof(ms); + GlobalMemoryStatusEx(&ms); + + return (julong)ms.ullAvailPhys; } julong os::physical_memory() { @@ -1579,16 +1580,17 @@ st->print("Memory:"); st->print(" %dk page", os::vm_page_size()>>10); - // FIXME: GlobalMemoryStatus() may return incorrect value if total memory - // is larger than 4GB - MEMORYSTATUS ms; - GlobalMemoryStatus(&ms); + // Use GlobalMemoryStatusEx() because GlobalMemoryStatus() may return incorrect + // value if total memory is larger than 4GB + MEMORYSTATUSEX ms; + ms.dwLength = sizeof(ms); + GlobalMemoryStatusEx(&ms); st->print(", physical %uk", os::physical_memory() >> 10); st->print("(%uk free)", os::available_memory() >> 10); - st->print(", swap %uk", ms.dwTotalPageFile >> 10); - st->print("(%uk free)", ms.dwAvailPageFile >> 10); + st->print(", swap %uk", ms.ullTotalPageFile >> 10); + st->print("(%uk free)", ms.ullAvailPageFile >> 10); st->cr(); } @@ -3135,11 +3137,13 @@ _processor_level = si.wProcessorLevel; _processor_count = si.dwNumberOfProcessors; - MEMORYSTATUS ms; + MEMORYSTATUSEX ms; + ms.dwLength = sizeof(ms); + // also returns dwAvailPhys (free physical memory bytes), dwTotalVirtual, dwAvailVirtual, // dwMemoryLoad (% of memory in use) - GlobalMemoryStatus(&ms); - _physical_memory = ms.dwTotalPhys; + GlobalMemoryStatusEx(&ms); + _physical_memory = ms.ullTotalPhys; OSVERSIONINFO oi; oi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.inline.hpp --- a/hotspot/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.inline.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.inline.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -46,6 +46,8 @@ inline void Atomic::dec_ptr(volatile intptr_t* dest) { (void)add_ptr(-1, dest); } inline void Atomic::dec_ptr(volatile void* dest) { (void)add_ptr(-1, dest); } +inline jlong Atomic::load(volatile jlong* src) { return *src; } + #ifdef _GNU_SOURCE inline jint Atomic::add (jint add_value, volatile jint* dest) { diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.inline.hpp --- a/hotspot/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.inline.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.inline.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -99,6 +99,8 @@ return (void*)_Atomic_cmpxchg_long((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, (int) os::is_MP()); } +inline jlong Atomic::load(volatile jlong* src) { return *src; } + #else // !AMD64 inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) { @@ -131,6 +133,15 @@ inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value) { return (void*)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value); } + +extern "C" void _Atomic_load_long(volatile jlong* src, volatile jlong* dst); + +inline jlong Atomic::load(volatile jlong* src) { + volatile jlong dest; + _Atomic_load_long(src, &dest); + return dest; +} + #endif // AMD64 #ifdef _GNU_SOURCE diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_32.il --- a/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_32.il Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_32.il Wed Jul 05 16:59:43 2017 +0200 @@ -97,6 +97,15 @@ popl %ebx .end + // Support for void Atomic::load(volatile jlong* src, volatile jlong* dest). + .inline _Atomic_load_long,2 + movl 0(%esp), %eax // src + fildll (%eax) + movl 4(%esp), %eax // dest + fistpll (%eax) + .end + + // Support for OrderAccess::acquire() .inline _OrderAccess_acquire,0 movl 0(%esp), %eax diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/c1/c1_IR.cpp --- a/hotspot/src/share/vm/c1/c1_IR.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/c1/c1_IR.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -208,6 +208,15 @@ return scope->caller_bci(); } +bool IRScopeDebugInfo::should_reexecute() { + ciMethod* cur_method = scope()->method(); + int cur_bci = bci(); + if (cur_method != NULL && cur_bci != SynchronizationEntryBCI) { + Bytecodes::Code code = cur_method->java_code_at_bci(cur_bci); + return Interpreter::bytecode_should_reexecute(code); + } else + return false; +} // Implementation of CodeEmitInfo @@ -253,7 +262,7 @@ void CodeEmitInfo::record_debug_info(DebugInformationRecorder* recorder, int pc_offset) { // record the safepoint before recording the debug info for enclosing scopes recorder->add_safepoint(pc_offset, _oop_map->deep_copy()); - _scope_debug_info->record_debug_info(recorder, pc_offset); + _scope_debug_info->record_debug_info(recorder, pc_offset, true/*topmost*/); recorder->end_safepoint(pc_offset); } diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/c1/c1_IR.hpp --- a/hotspot/src/share/vm/c1/c1_IR.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/c1/c1_IR.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -239,15 +239,20 @@ GrowableArray* monitors() { return _monitors; } IRScopeDebugInfo* caller() { return _caller; } - void record_debug_info(DebugInformationRecorder* recorder, int pc_offset) { + //Whether we should reexecute this bytecode for deopt + bool should_reexecute(); + + void record_debug_info(DebugInformationRecorder* recorder, int pc_offset, bool topmost) { if (caller() != NULL) { // Order is significant: Must record caller first. - caller()->record_debug_info(recorder, pc_offset); + caller()->record_debug_info(recorder, pc_offset, false/*topmost*/); } DebugToken* locvals = recorder->create_scope_values(locals()); DebugToken* expvals = recorder->create_scope_values(expressions()); DebugToken* monvals = recorder->create_monitor_values(monitors()); - recorder->describe_scope(pc_offset, scope()->method(), bci(), locvals, expvals, monvals); + // reexecute allowed only for the topmost frame + bool reexecute = topmost ? should_reexecute() : false; + recorder->describe_scope(pc_offset, scope()->method(), bci(), reexecute, locvals, expvals, monvals); } }; diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/c1/c1_LIRAssembler.cpp --- a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -379,7 +379,8 @@ ValueStack* s = nth_oldest(vstack, n, s_bci); if (s == NULL) break; IRScope* scope = s->scope(); - debug_info->describe_scope(pc_offset, scope->method(), s_bci); + //Always pass false for reexecute since these ScopeDescs are never used for deopt + debug_info->describe_scope(pc_offset, scope->method(), s_bci, false/*reexecute*/); } debug_info->end_non_safepoint(pc_offset); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/ci/ciObjectFactory.cpp --- a/hotspot/src/share/vm/ci/ciObjectFactory.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/ci/ciObjectFactory.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -219,24 +219,27 @@ ASSERT_IN_VM; #ifdef ASSERT - oop last = NULL; - for (int j = 0; j< _ci_objects->length(); j++) { - oop o = _ci_objects->at(j)->get_oop(); - assert(last < o, "out of order"); - last = o; + if (CIObjectFactoryVerify) { + oop last = NULL; + for (int j = 0; j< _ci_objects->length(); j++) { + oop o = _ci_objects->at(j)->get_oop(); + assert(last < o, "out of order"); + last = o; + } } #endif // ASSERT int len = _ci_objects->length(); int index = find(key, _ci_objects); #ifdef ASSERT - for (int i=0; i<_ci_objects->length(); i++) { - if (_ci_objects->at(i)->get_oop() == key) { - assert(index == i, " bad lookup"); + if (CIObjectFactoryVerify) { + for (int i=0; i<_ci_objects->length(); i++) { + if (_ci_objects->at(i)->get_oop() == key) { + assert(index == i, " bad lookup"); + } } } #endif if (!is_found_at(index, key, _ci_objects)) { - // Check in the non-perm area before putting it in the list. NonPermObject* &bucket = find_non_perm(key); if (bucket != NULL) { @@ -539,11 +542,13 @@ objects->at_put(index, obj); } #ifdef ASSERT - oop last = NULL; - for (int j = 0; j< objects->length(); j++) { - oop o = objects->at(j)->get_oop(); - assert(last < o, "out of order"); - last = o; + if (CIObjectFactoryVerify) { + oop last = NULL; + for (int j = 0; j< objects->length(); j++) { + oop o = objects->at(j)->get_oop(); + assert(last < o, "out of order"); + last = o; + } } #endif // ASSERT } diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/classfile/classFileParser.cpp --- a/hotspot/src/share/vm/classfile/classFileParser.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -547,7 +547,6 @@ int length, Handle class_loader, Handle protection_domain, - PerfTraceTime* vmtimer, symbolHandle class_name, TRAPS) { ClassFileStream* cfs = stream(); @@ -575,13 +574,11 @@ guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY, "Bad interface name in class file %s", CHECK_(nullHandle)); - vmtimer->suspend(); // do not count recursive loading twice // Call resolve_super so classcircularity is checked klassOop k = SystemDictionary::resolve_super_or_fail(class_name, unresolved_klass, class_loader, protection_domain, false, CHECK_(nullHandle)); interf = KlassHandle(THREAD, k); - vmtimer->resume(); if (LinkWellKnownClasses) // my super type is well known to me cp->klass_at_put(interface_index, interf()); // eagerly resolve @@ -2558,7 +2555,15 @@ ClassFileStream* cfs = stream(); // Timing - PerfTraceTime vmtimer(ClassLoader::perf_accumulated_time()); + assert(THREAD->is_Java_thread(), "must be a JavaThread"); + JavaThread* jt = (JavaThread*) THREAD; + + PerfClassTraceTime ctimer(ClassLoader::perf_class_parse_time(), + ClassLoader::perf_class_parse_selftime(), + NULL, + jt->get_thread_stat()->perf_recursion_counts_addr(), + jt->get_thread_stat()->perf_timers_addr(), + PerfClassTraceTime::PARSE_CLASS); _has_finalizer = _has_empty_finalizer = _has_vanilla_constructor = false; @@ -2738,7 +2743,7 @@ if (itfs_len == 0) { local_interfaces = objArrayHandle(THREAD, Universe::the_empty_system_obj_array()); } else { - local_interfaces = parse_interfaces(cp, itfs_len, class_loader, protection_domain, &vmtimer, _class_name, CHECK_(nullHandle)); + local_interfaces = parse_interfaces(cp, itfs_len, class_loader, protection_domain, _class_name, CHECK_(nullHandle)); } // Fields (offsets are filled in later) @@ -2782,6 +2787,7 @@ protection_domain, true, CHECK_(nullHandle)); + KlassHandle kh (THREAD, k); super_klass = instanceKlassHandle(THREAD, kh()); if (LinkWellKnownClasses) // my super class is well known to me diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/classfile/classFileParser.hpp --- a/hotspot/src/share/vm/classfile/classFileParser.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/classfile/classFileParser.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -61,7 +61,6 @@ int length, Handle class_loader, Handle protection_domain, - PerfTraceTime* vmtimer, symbolHandle class_name, TRAPS); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/classfile/classLoader.cpp --- a/hotspot/src/share/vm/classfile/classLoader.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/classfile/classLoader.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -48,9 +48,26 @@ PerfCounter* ClassLoader::_perf_accumulated_time = NULL; PerfCounter* ClassLoader::_perf_classes_inited = NULL; PerfCounter* ClassLoader::_perf_class_init_time = NULL; +PerfCounter* ClassLoader::_perf_class_init_selftime = NULL; +PerfCounter* ClassLoader::_perf_classes_verified = NULL; PerfCounter* ClassLoader::_perf_class_verify_time = NULL; +PerfCounter* ClassLoader::_perf_class_verify_selftime = NULL; PerfCounter* ClassLoader::_perf_classes_linked = NULL; PerfCounter* ClassLoader::_perf_class_link_time = NULL; +PerfCounter* ClassLoader::_perf_class_link_selftime = NULL; +PerfCounter* ClassLoader::_perf_class_parse_time = NULL; +PerfCounter* ClassLoader::_perf_class_parse_selftime = NULL; +PerfCounter* ClassLoader::_perf_sys_class_lookup_time = NULL; +PerfCounter* ClassLoader::_perf_shared_classload_time = NULL; +PerfCounter* ClassLoader::_perf_sys_classload_time = NULL; +PerfCounter* ClassLoader::_perf_app_classload_time = NULL; +PerfCounter* ClassLoader::_perf_app_classload_selftime = NULL; +PerfCounter* ClassLoader::_perf_app_classload_count = NULL; +PerfCounter* ClassLoader::_perf_define_appclasses = NULL; +PerfCounter* ClassLoader::_perf_define_appclass_time = NULL; +PerfCounter* ClassLoader::_perf_define_appclass_selftime = NULL; +PerfCounter* ClassLoader::_perf_app_classfile_bytes_read = NULL; +PerfCounter* ClassLoader::_perf_sys_classfile_bytes_read = NULL; PerfCounter* ClassLoader::_sync_systemLoaderLockContentionRate = NULL; PerfCounter* ClassLoader::_sync_nonSystemLoaderLockContentionRate = NULL; PerfCounter* ClassLoader::_sync_JVMFindLoadedClassLockFreeCounter = NULL; @@ -152,6 +169,9 @@ hpi::close(file_handle); // construct ClassFileStream if (num_read == (size_t)st.st_size) { + if (UsePerfData) { + ClassLoader::perf_sys_classfile_bytes_read()->inc(num_read); + } return new ClassFileStream(buffer, st.st_size, _dir); // Resource allocated } } @@ -198,6 +218,9 @@ buffer = NEW_RESOURCE_ARRAY(u1, filesize); if (!(*ReadEntry)(_zip, entry, buffer, filename)) return NULL; } + if (UsePerfData) { + ClassLoader::perf_sys_classfile_bytes_read()->inc(filesize); + } // return result return new ClassFileStream(buffer, filesize, _zip_name); // Resource allocated } @@ -825,7 +848,9 @@ ClassFileStream* stream = NULL; int classpath_index = 0; { - PerfTraceTime vmtimer(perf_accumulated_time()); + PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(), + ((JavaThread*) THREAD)->get_thread_stat()->perf_timers_addr(), + PerfClassTraceTime::CLASS_LOAD); ClassPathEntry* e = _first_entry; while (e != NULL) { stream = e->open_stream(name); @@ -890,11 +915,29 @@ // jvmstat performance counters NEWPERFTICKCOUNTER(_perf_accumulated_time, SUN_CLS, "time"); NEWPERFTICKCOUNTER(_perf_class_init_time, SUN_CLS, "classInitTime"); + NEWPERFTICKCOUNTER(_perf_class_init_selftime, SUN_CLS, "classInitTime.self"); NEWPERFTICKCOUNTER(_perf_class_verify_time, SUN_CLS, "classVerifyTime"); + NEWPERFTICKCOUNTER(_perf_class_verify_selftime, SUN_CLS, "classVerifyTime.self"); NEWPERFTICKCOUNTER(_perf_class_link_time, SUN_CLS, "classLinkedTime"); - + NEWPERFTICKCOUNTER(_perf_class_link_selftime, SUN_CLS, "classLinkedTime.self"); NEWPERFEVENTCOUNTER(_perf_classes_inited, SUN_CLS, "initializedClasses"); NEWPERFEVENTCOUNTER(_perf_classes_linked, SUN_CLS, "linkedClasses"); + NEWPERFEVENTCOUNTER(_perf_classes_verified, SUN_CLS, "verifiedClasses"); + + NEWPERFTICKCOUNTER(_perf_class_parse_time, SUN_CLS, "parseClassTime"); + NEWPERFTICKCOUNTER(_perf_class_parse_selftime, SUN_CLS, "parseClassTime.self"); + NEWPERFTICKCOUNTER(_perf_sys_class_lookup_time, SUN_CLS, "lookupSysClassTime"); + NEWPERFTICKCOUNTER(_perf_shared_classload_time, SUN_CLS, "sharedClassLoadTime"); + NEWPERFTICKCOUNTER(_perf_sys_classload_time, SUN_CLS, "sysClassLoadTime"); + NEWPERFTICKCOUNTER(_perf_app_classload_time, SUN_CLS, "appClassLoadTime"); + NEWPERFTICKCOUNTER(_perf_app_classload_selftime, SUN_CLS, "appClassLoadTime.self"); + NEWPERFEVENTCOUNTER(_perf_app_classload_count, SUN_CLS, "appClassLoadCount"); + NEWPERFTICKCOUNTER(_perf_define_appclasses, SUN_CLS, "defineAppClasses"); + NEWPERFTICKCOUNTER(_perf_define_appclass_time, SUN_CLS, "defineAppClassTime"); + NEWPERFTICKCOUNTER(_perf_define_appclass_selftime, SUN_CLS, "defineAppClassTime.self"); + NEWPERFBYTECOUNTER(_perf_app_classfile_bytes_read, SUN_CLS, "appClassBytes"); + NEWPERFBYTECOUNTER(_perf_sys_classfile_bytes_read, SUN_CLS, "sysClassBytes"); + // The following performance counters are added for measuring the impact // of the bug fix of 6365597. They are mainly focused on finding out diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/classfile/classLoader.hpp --- a/hotspot/src/share/vm/classfile/classLoader.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/classfile/classLoader.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -149,9 +149,26 @@ static PerfCounter* _perf_accumulated_time; static PerfCounter* _perf_classes_inited; static PerfCounter* _perf_class_init_time; + static PerfCounter* _perf_class_init_selftime; + static PerfCounter* _perf_classes_verified; static PerfCounter* _perf_class_verify_time; + static PerfCounter* _perf_class_verify_selftime; static PerfCounter* _perf_classes_linked; static PerfCounter* _perf_class_link_time; + static PerfCounter* _perf_class_link_selftime; + static PerfCounter* _perf_class_parse_time; + static PerfCounter* _perf_class_parse_selftime; + static PerfCounter* _perf_sys_class_lookup_time; + static PerfCounter* _perf_shared_classload_time; + static PerfCounter* _perf_sys_classload_time; + static PerfCounter* _perf_app_classload_time; + static PerfCounter* _perf_app_classload_selftime; + static PerfCounter* _perf_app_classload_count; + static PerfCounter* _perf_define_appclasses; + static PerfCounter* _perf_define_appclass_time; + static PerfCounter* _perf_define_appclass_selftime; + static PerfCounter* _perf_app_classfile_bytes_read; + static PerfCounter* _perf_sys_classfile_bytes_read; static PerfCounter* _sync_systemLoaderLockContentionRate; static PerfCounter* _sync_nonSystemLoaderLockContentionRate; @@ -196,12 +213,29 @@ static void print_bootclasspath(); // Timing - static PerfCounter* perf_accumulated_time() { return _perf_accumulated_time; } - static PerfCounter* perf_classes_inited() { return _perf_classes_inited; } - static PerfCounter* perf_class_init_time() { return _perf_class_init_time; } - static PerfCounter* perf_class_verify_time() { return _perf_class_verify_time; } - static PerfCounter* perf_classes_linked() { return _perf_classes_linked; } - static PerfCounter* perf_class_link_time() { return _perf_class_link_time; } + static PerfCounter* perf_accumulated_time() { return _perf_accumulated_time; } + static PerfCounter* perf_classes_inited() { return _perf_classes_inited; } + static PerfCounter* perf_class_init_time() { return _perf_class_init_time; } + static PerfCounter* perf_class_init_selftime() { return _perf_class_init_selftime; } + static PerfCounter* perf_classes_verified() { return _perf_classes_verified; } + static PerfCounter* perf_class_verify_time() { return _perf_class_verify_time; } + static PerfCounter* perf_class_verify_selftime() { return _perf_class_verify_selftime; } + static PerfCounter* perf_classes_linked() { return _perf_classes_linked; } + static PerfCounter* perf_class_link_time() { return _perf_class_link_time; } + static PerfCounter* perf_class_link_selftime() { return _perf_class_link_selftime; } + static PerfCounter* perf_class_parse_time() { return _perf_class_parse_time; } + static PerfCounter* perf_class_parse_selftime() { return _perf_class_parse_selftime; } + static PerfCounter* perf_sys_class_lookup_time() { return _perf_sys_class_lookup_time; } + static PerfCounter* perf_shared_classload_time() { return _perf_shared_classload_time; } + static PerfCounter* perf_sys_classload_time() { return _perf_sys_classload_time; } + static PerfCounter* perf_app_classload_time() { return _perf_app_classload_time; } + static PerfCounter* perf_app_classload_selftime() { return _perf_app_classload_selftime; } + static PerfCounter* perf_app_classload_count() { return _perf_app_classload_count; } + static PerfCounter* perf_define_appclasses() { return _perf_define_appclasses; } + static PerfCounter* perf_define_appclass_time() { return _perf_define_appclass_time; } + static PerfCounter* perf_define_appclass_selftime() { return _perf_define_appclass_selftime; } + static PerfCounter* perf_app_classfile_bytes_read() { return _perf_app_classfile_bytes_read; } + static PerfCounter* perf_sys_classfile_bytes_read() { return _perf_sys_classfile_bytes_read; } // Record how often system loader lock object is contended static PerfCounter* sync_systemLoaderLockContentionRate() { @@ -307,3 +341,118 @@ static int compile_the_world_counter() { return _compile_the_world_counter; } #endif //PRODUCT }; + +// PerfClassTraceTime is used to measure time for class loading related events. +// This class tracks cumulative time and exclusive time for specific event types. +// During the execution of one event, other event types (e.g. class loading and +// resolution) as well as recursive calls of the same event type could happen. +// Only one elapsed timer (cumulative) and one thread-local self timer (exclusive) +// (i.e. only one event type) are active at a time even multiple PerfClassTraceTime +// instances have been created as multiple events are happening. +class PerfClassTraceTime { + public: + enum { + CLASS_LOAD = 0, + PARSE_CLASS = 1, + CLASS_LINK = 2, + CLASS_VERIFY = 3, + CLASS_CLINIT = 4, + DEFINE_CLASS = 5, + EVENT_TYPE_COUNT = 6 + }; + protected: + // _t tracks time from initialization to destruction of this timer instance + // including time for all other event types, and recursive calls of this type. + // When a timer is called recursively, the elapsedTimer _t would not be used. + elapsedTimer _t; + PerfLongCounter* _timep; + PerfLongCounter* _selftimep; + PerfLongCounter* _eventp; + // pointer to thread-local recursion counter and timer array + // The thread_local timers track cumulative time for specific event types + // exclusive of time for other event types, but including recursive calls + // of the same type. + int* _recursion_counters; + elapsedTimer* _timers; + int _event_type; + int _prev_active_event; + + public: + + inline PerfClassTraceTime(PerfLongCounter* timep, /* counter incremented with inclusive time */ + PerfLongCounter* selftimep, /* counter incremented with exclusive time */ + PerfLongCounter* eventp, /* event counter */ + int* recursion_counters, /* thread-local recursion counter array */ + elapsedTimer* timers, /* thread-local timer array */ + int type /* event type */ ) : + _timep(timep), _selftimep(selftimep), _eventp(eventp), _recursion_counters(recursion_counters), _timers(timers), _event_type(type) { + initialize(); + } + + inline PerfClassTraceTime(PerfLongCounter* timep, /* counter incremented with inclusive time */ + elapsedTimer* timers, /* thread-local timer array */ + int type /* event type */ ) : + _timep(timep), _selftimep(NULL), _eventp(NULL), _recursion_counters(NULL), _timers(timers), _event_type(type) { + initialize(); + } + + void initialize() { + if (!UsePerfData) return; + + if (_eventp != NULL) { + // increment the event counter + _eventp->inc(); + } + + // stop the current active thread-local timer to measure inclusive time + _prev_active_event = -1; + for (int i=0; i < EVENT_TYPE_COUNT; i++) { + if (_timers[i].is_active()) { + assert(_prev_active_event == -1, "should have only one active timer"); + _prev_active_event = i; + _timers[i].stop(); + } + } + + if (_recursion_counters == NULL || (_recursion_counters[_event_type])++ == 0) { + // start the inclusive timer if not recursively called + _t.start(); + } + + // start thread-local timer of the given event type + if (!_timers[_event_type].is_active()) { + _timers[_event_type].start(); + } + } + + inline void suspend() { _t.stop(); _timers[_event_type].stop(); } + inline void resume() { _t.start(); _timers[_event_type].start(); } + + ~PerfClassTraceTime() { + if (!UsePerfData) return; + + // stop the thread-local timer as the event completes + // and resume the thread-local timer of the event next on the stack + _timers[_event_type].stop(); + jlong selftime = _timers[_event_type].ticks(); + + if (_prev_active_event >= 0) { + _timers[_prev_active_event].start(); + } + + if (_recursion_counters != NULL && --(_recursion_counters[_event_type]) > 0) return; + + // increment the counters only on the leaf call + _t.stop(); + _timep->inc(_t.ticks()); + if (_selftimep != NULL) { + _selftimep->inc(selftime); + } + // add all class loading related event selftime to the accumulated time counter + ClassLoader::perf_accumulated_time()->inc(selftime); + + // reset the timer + _timers[_event_type].reset(); + } +}; + diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/classfile/javaClasses.cpp --- a/hotspot/src/share/vm/classfile/javaClasses.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -1229,10 +1229,13 @@ // Compiled java method case. if (decode_offset != 0) { + bool dummy_reexecute = false; DebugInfoReadStream stream(nm, decode_offset); decode_offset = stream.read_int(); method = (methodOop)nm->oop_at(stream.read_int()); - bci = stream.read_bci(); + //fill_in_stack_trace does not need the reexecute information which is designed + //for the deopt to reexecute + bci = stream.read_bci_and_reexecute(dummy_reexecute); } else { if (fr.is_first_frame()) break; address pc = fr.pc(); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/classfile/systemDictionary.cpp --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -1306,13 +1306,18 @@ instanceKlassHandle SystemDictionary::load_instance_class(symbolHandle class_name, Handle class_loader, TRAPS) { instanceKlassHandle nh = instanceKlassHandle(); // null Handle if (class_loader.is_null()) { + // Search the shared system dictionary for classes preloaded into the // shared spaces. instanceKlassHandle k; - k = load_shared_class(class_name, class_loader, THREAD); + { + PerfTraceTime vmtimer(ClassLoader::perf_shared_classload_time()); + k = load_shared_class(class_name, class_loader, THREAD); + } if (k.is_null()) { // Use VM class loader + PerfTraceTime vmtimer(ClassLoader::perf_sys_classload_time()); k = ClassLoader::load_classfile(class_name, CHECK_(nh)); } @@ -1334,6 +1339,16 @@ // Use user specified class loader to load class. Call loadClass operation on class_loader. ResourceMark rm(THREAD); + assert(THREAD->is_Java_thread(), "must be a JavaThread"); + JavaThread* jt = (JavaThread*) THREAD; + + PerfClassTraceTime vmtimer(ClassLoader::perf_app_classload_time(), + ClassLoader::perf_app_classload_selftime(), + ClassLoader::perf_app_classload_count(), + jt->get_thread_stat()->perf_recursion_counts_addr(), + jt->get_thread_stat()->perf_timers_addr(), + PerfClassTraceTime::CLASS_LOAD); + Handle s = java_lang_String::create_from_symbol(class_name, CHECK_(nh)); // Translate to external class name format, i.e., convert '/' chars to '.' Handle string = java_lang_String::externalize_classname(s, CHECK_(nh)); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/code/debugInfo.hpp --- a/hotspot/src/share/vm/code/debugInfo.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/code/debugInfo.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -255,7 +255,8 @@ ScopeValue* read_object_value(); ScopeValue* get_cached_object(); // BCI encoding is mostly unsigned, but -1 is a distinguished value - int read_bci() { return read_int() + InvocationEntryBci; } + // Decoding based on encoding: bci = InvocationEntryBci + read_int()/2; reexecute = read_int()%2 == 1 ? true : false; + int read_bci_and_reexecute(bool& reexecute) { int i = read_int(); reexecute = (i & 1) ? true : false; return (i >> 1) + InvocationEntryBci; } }; // DebugInfoWriteStream specializes CompressedWriteStream for @@ -268,5 +269,6 @@ public: DebugInfoWriteStream(DebugInformationRecorder* recorder, int initial_size); void write_handle(jobject h); - void write_bci(int bci) { write_int(bci - InvocationEntryBci); } + //Encoding bci and reexecute into one word as (bci - InvocationEntryBci)*2 + reexecute + void write_bci_and_reexecute(int bci, bool reexecute) { write_int(((bci - InvocationEntryBci) << 1) + (reexecute ? 1 : 0)); } }; diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/code/debugInfoRec.cpp --- a/hotspot/src/share/vm/code/debugInfoRec.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/code/debugInfoRec.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -280,6 +280,7 @@ void DebugInformationRecorder::describe_scope(int pc_offset, ciMethod* method, int bci, + bool reexecute, DebugToken* locals, DebugToken* expressions, DebugToken* monitors) { @@ -297,7 +298,7 @@ // serialize scope jobject method_enc = (method == NULL)? NULL: method->encoding(); stream()->write_int(oop_recorder()->find_index(method_enc)); - stream()->write_bci(bci); + stream()->write_bci_and_reexecute(bci, reexecute); assert(method == NULL || (method->is_native() && bci == 0) || (!method->is_native() && 0 <= bci && bci < method->code_size()) || diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/code/debugInfoRec.hpp --- a/hotspot/src/share/vm/code/debugInfoRec.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/code/debugInfoRec.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -87,6 +87,7 @@ void describe_scope(int pc_offset, ciMethod* method, int bci, + bool reexecute, DebugToken* locals = NULL, DebugToken* expressions = NULL, DebugToken* monitors = NULL); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/code/scopeDesc.cpp --- a/hotspot/src/share/vm/code/scopeDesc.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/code/scopeDesc.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -46,6 +46,7 @@ _decode_offset = parent->_sender_decode_offset; _objects = parent->_objects; decode_body(); + assert(_reexecute == false, "reexecute not allowed"); } @@ -56,6 +57,7 @@ _sender_decode_offset = DebugInformationRecorder::serialized_null; _method = methodHandle(_code->method()); _bci = InvocationEntryBci; + _reexecute = false; _locals_decode_offset = DebugInformationRecorder::serialized_null; _expressions_decode_offset = DebugInformationRecorder::serialized_null; _monitors_decode_offset = DebugInformationRecorder::serialized_null; @@ -65,7 +67,8 @@ _sender_decode_offset = stream->read_int(); _method = methodHandle((methodOop) stream->read_oop()); - _bci = stream->read_bci(); + _bci = stream->read_bci_and_reexecute(_reexecute); + // decode offsets for body and sender _locals_decode_offset = stream->read_int(); _expressions_decode_offset = stream->read_int(); @@ -170,6 +173,7 @@ st->print("ScopeDesc[%d]@" PTR_FORMAT " ", _decode_offset, _code->instructions_begin()); st->print_cr(" offset: %d", _decode_offset); st->print_cr(" bci: %d", bci()); + st->print_cr(" reexecute: %s", should_reexecute() ? "true" : "false"); st->print_cr(" locals: %d", _locals_decode_offset); st->print_cr(" stack: %d", _expressions_decode_offset); st->print_cr(" monitor: %d", _monitors_decode_offset); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/code/scopeDesc.hpp --- a/hotspot/src/share/vm/code/scopeDesc.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/code/scopeDesc.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -39,7 +39,8 @@ DebugInfoReadStream buffer(code, pc_desc->scope_decode_offset()); int ignore_sender = buffer.read_int(); _method = methodOop(buffer.read_oop()); - _bci = buffer.read_bci(); + bool dummy_reexecute; //only methodOop and bci are needed! + _bci = buffer.read_bci_and_reexecute(dummy_reexecute); } methodOop method() { return _method; } @@ -60,8 +61,9 @@ ScopeDesc(const nmethod* code, int decode_offset); // JVM state - methodHandle method() const { return _method; } - int bci() const { return _bci; } + methodHandle method() const { return _method; } + int bci() const { return _bci; } + bool should_reexecute() const { return _reexecute; } GrowableArray* locals(); GrowableArray* expressions(); @@ -86,6 +88,7 @@ // JVM state methodHandle _method; int _bci; + bool _reexecute; // Decoding offsets int _decode_offset; diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -25,11 +25,21 @@ #include "incls/_precompiled.incl" #include "incls/_concurrentG1Refine.cpp.incl" +// Possible sizes for the card counts cache: odd primes that roughly double in size. +// (See jvmtiTagMap.cpp). +int ConcurrentG1Refine::_cc_cache_sizes[] = { + 16381, 32771, 76831, 150001, 307261, + 614563, 1228891, 2457733, 4915219, 9830479, + 19660831, 39321619, 78643219, 157286461, -1 + }; + ConcurrentG1Refine::ConcurrentG1Refine() : - _card_counts(NULL), _cur_card_count_histo(NULL), _cum_card_count_histo(NULL), + _card_counts(NULL), _card_epochs(NULL), + _n_card_counts(0), _max_n_card_counts(0), + _cache_size_index(0), _expand_card_counts(false), _hot_cache(NULL), _def_use_cache(false), _use_cache(false), - _n_periods(0), _total_cards(0), _total_travs(0), + _n_periods(0), _threads(NULL), _n_threads(0) { if (G1ConcRefine) { @@ -57,32 +67,51 @@ } void ConcurrentG1Refine::init() { - if (G1ConcRSLogCacheSize > 0 || G1ConcRSCountTraversals) { - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - _n_card_counts = - (unsigned) (g1h->g1_reserved_obj_bytes() >> CardTableModRefBS::card_shift); - _card_counts = NEW_C_HEAP_ARRAY(unsigned char, _n_card_counts); - for (size_t i = 0; i < _n_card_counts; i++) _card_counts[i] = 0; - ModRefBarrierSet* bs = g1h->mr_bs(); + if (G1ConcRSLogCacheSize > 0) { + _g1h = G1CollectedHeap::heap(); + _max_n_card_counts = + (unsigned) (_g1h->g1_reserved_obj_bytes() >> CardTableModRefBS::card_shift); + + size_t max_card_num = ((size_t)1 << (sizeof(unsigned)*BitsPerByte-1)) - 1; + guarantee(_max_n_card_counts < max_card_num, "card_num representation"); + + int desired = _max_n_card_counts / InitialCacheFraction; + for (_cache_size_index = 0; + _cc_cache_sizes[_cache_size_index] >= 0; _cache_size_index++) { + if (_cc_cache_sizes[_cache_size_index] >= desired) break; + } + _cache_size_index = MAX2(0, (_cache_size_index - 1)); + + int initial_size = _cc_cache_sizes[_cache_size_index]; + if (initial_size < 0) initial_size = _max_n_card_counts; + + // Make sure we don't go bigger than we will ever need + _n_card_counts = MIN2((unsigned) initial_size, _max_n_card_counts); + + _card_counts = NEW_C_HEAP_ARRAY(CardCountCacheEntry, _n_card_counts); + _card_epochs = NEW_C_HEAP_ARRAY(CardEpochCacheEntry, _n_card_counts); + + Copy::fill_to_bytes(&_card_counts[0], + _n_card_counts * sizeof(CardCountCacheEntry)); + Copy::fill_to_bytes(&_card_epochs[0], _n_card_counts * sizeof(CardEpochCacheEntry)); + + ModRefBarrierSet* bs = _g1h->mr_bs(); guarantee(bs->is_a(BarrierSet::CardTableModRef), "Precondition"); - CardTableModRefBS* ctbs = (CardTableModRefBS*)bs; - _ct_bot = ctbs->byte_for_const(g1h->reserved_region().start()); - if (G1ConcRSCountTraversals) { - _cur_card_count_histo = NEW_C_HEAP_ARRAY(unsigned, 256); - _cum_card_count_histo = NEW_C_HEAP_ARRAY(unsigned, 256); - for (int i = 0; i < 256; i++) { - _cur_card_count_histo[i] = 0; - _cum_card_count_histo[i] = 0; - } - } - } - if (G1ConcRSLogCacheSize > 0) { + _ct_bs = (CardTableModRefBS*)bs; + _ct_bot = _ct_bs->byte_for_const(_g1h->reserved_region().start()); + _def_use_cache = true; _use_cache = true; _hot_cache_size = (1 << G1ConcRSLogCacheSize); _hot_cache = NEW_C_HEAP_ARRAY(jbyte*, _hot_cache_size); _n_hot = 0; _hot_cache_idx = 0; + + // For refining the cards in the hot cache in parallel + int n_workers = (ParallelGCThreads > 0 ? + _g1h->workers()->total_workers() : 1); + _hot_cache_par_chunk_size = MAX2(1, _hot_cache_size / n_workers); + _hot_cache_par_claimed_idx = 0; } } @@ -95,15 +124,11 @@ } ConcurrentG1Refine::~ConcurrentG1Refine() { - if (G1ConcRSLogCacheSize > 0 || G1ConcRSCountTraversals) { + if (G1ConcRSLogCacheSize > 0) { assert(_card_counts != NULL, "Logic"); - FREE_C_HEAP_ARRAY(unsigned char, _card_counts); - assert(_cur_card_count_histo != NULL, "Logic"); - FREE_C_HEAP_ARRAY(unsigned, _cur_card_count_histo); - assert(_cum_card_count_histo != NULL, "Logic"); - FREE_C_HEAP_ARRAY(unsigned, _cum_card_count_histo); - } - if (G1ConcRSLogCacheSize > 0) { + FREE_C_HEAP_ARRAY(CardCountCacheEntry, _card_counts); + assert(_card_epochs != NULL, "Logic"); + FREE_C_HEAP_ARRAY(CardEpochCacheEntry, _card_epochs); assert(_hot_cache != NULL, "Logic"); FREE_C_HEAP_ARRAY(jbyte*, _hot_cache); } @@ -123,165 +148,232 @@ } } - -int ConcurrentG1Refine::add_card_count(jbyte* card_ptr) { - size_t card_num = (card_ptr - _ct_bot); - guarantee(0 <= card_num && card_num < _n_card_counts, "Bounds"); - unsigned char cnt = _card_counts[card_num]; - if (cnt < 255) _card_counts[card_num]++; - return cnt; - _total_travs++; +bool ConcurrentG1Refine::is_young_card(jbyte* card_ptr) { + HeapWord* start = _ct_bs->addr_for(card_ptr); + HeapRegion* r = _g1h->heap_region_containing(start); + if (r != NULL && r->is_young()) { + return true; + } + // This card is not associated with a heap region + // so can't be young. + return false; } -jbyte* ConcurrentG1Refine::cache_insert(jbyte* card_ptr) { - int count = add_card_count(card_ptr); - // Count previously unvisited cards. - if (count == 0) _total_cards++; - // We'll assume a traversal unless we store it in the cache. +jbyte* ConcurrentG1Refine::add_card_count(jbyte* card_ptr, int* count, bool* defer) { + unsigned new_card_num = ptr_2_card_num(card_ptr); + unsigned bucket = hash(new_card_num); + assert(0 <= bucket && bucket < _n_card_counts, "Bounds"); + + CardCountCacheEntry* count_ptr = &_card_counts[bucket]; + CardEpochCacheEntry* epoch_ptr = &_card_epochs[bucket]; + + // We have to construct a new entry if we haven't updated the counts + // during the current period, or if the count was updated for a + // different card number. + unsigned int new_epoch = (unsigned int) _n_periods; + julong new_epoch_entry = make_epoch_entry(new_card_num, new_epoch); + + while (true) { + // Fetch the previous epoch value + julong prev_epoch_entry = epoch_ptr->_value; + julong cas_res; + + if (extract_epoch(prev_epoch_entry) != new_epoch) { + // This entry has not yet been updated during this period. + // Note: we update the epoch value atomically to ensure + // that there is only one winner that updates the cached + // card_ptr value even though all the refine threads share + // the same epoch value. + + cas_res = (julong) Atomic::cmpxchg((jlong) new_epoch_entry, + (volatile jlong*)&epoch_ptr->_value, + (jlong) prev_epoch_entry); + + if (cas_res == prev_epoch_entry) { + // We have successfully won the race to update the + // epoch and card_num value. Make it look like the + // count and eviction count were previously cleared. + count_ptr->_count = 1; + count_ptr->_evict_count = 0; + *count = 0; + // We can defer the processing of card_ptr + *defer = true; + return card_ptr; + } + // We did not win the race to update the epoch field, so some other + // thread must have done it. The value that gets returned by CAS + // should be the new epoch value. + assert(extract_epoch(cas_res) == new_epoch, "unexpected epoch"); + // We could 'continue' here or just re-read the previous epoch value + prev_epoch_entry = epoch_ptr->_value; + } + + // The epoch entry for card_ptr has been updated during this period. + unsigned old_card_num = extract_card_num(prev_epoch_entry); + + // The card count that will be returned to caller + *count = count_ptr->_count; + + // Are we updating the count for the same card? + if (new_card_num == old_card_num) { + // Same card - just update the count. We could have more than one + // thread racing to update count for the current card. It should be + // OK not to use a CAS as the only penalty should be some missed + // increments of the count which delays identifying the card as "hot". + + if (*count < max_jubyte) count_ptr->_count++; + // We can defer the processing of card_ptr + *defer = true; + return card_ptr; + } + + // Different card - evict old card info + if (count_ptr->_evict_count < max_jubyte) count_ptr->_evict_count++; + if (count_ptr->_evict_count > G1CardCountCacheExpandThreshold) { + // Trigger a resize the next time we clear + _expand_card_counts = true; + } + + cas_res = (julong) Atomic::cmpxchg((jlong) new_epoch_entry, + (volatile jlong*)&epoch_ptr->_value, + (jlong) prev_epoch_entry); + + if (cas_res == prev_epoch_entry) { + // We successfully updated the card num value in the epoch entry + count_ptr->_count = 0; // initialize counter for new card num + + // Even though the region containg the card at old_card_num was not + // in the young list when old_card_num was recorded in the epoch + // cache it could have been added to the free list and subsequently + // added to the young list in the intervening time. If the evicted + // card is in a young region just return the card_ptr and the evicted + // card will not be cleaned. See CR 6817995. + + jbyte* old_card_ptr = card_num_2_ptr(old_card_num); + if (is_young_card(old_card_ptr)) { + *count = 0; + // We can defer the processing of card_ptr + *defer = true; + return card_ptr; + } + + // We do not want to defer processing of card_ptr in this case + // (we need to refine old_card_ptr and card_ptr) + *defer = false; + return old_card_ptr; + } + // Someone else beat us - try again. + } +} + +jbyte* ConcurrentG1Refine::cache_insert(jbyte* card_ptr, bool* defer) { + int count; + jbyte* cached_ptr = add_card_count(card_ptr, &count, defer); + assert(cached_ptr != NULL, "bad cached card ptr"); + assert(!is_young_card(cached_ptr), "shouldn't get a card in young region"); + + // The card pointer we obtained from card count cache is not hot + // so do not store it in the cache; return it for immediate + // refining. if (count < G1ConcRSHotCardLimit) { - _total_travs++; - return card_ptr; + return cached_ptr; } - // Otherwise, it's hot. + + // Otherwise, the pointer we got from the _card_counts is hot. jbyte* res = NULL; MutexLockerEx x(HotCardCache_lock, Mutex::_no_safepoint_check_flag); if (_n_hot == _hot_cache_size) { - _total_travs++; res = _hot_cache[_hot_cache_idx]; _n_hot--; } // Now _n_hot < _hot_cache_size, and we can insert at _hot_cache_idx. - _hot_cache[_hot_cache_idx] = card_ptr; + _hot_cache[_hot_cache_idx] = cached_ptr; _hot_cache_idx++; if (_hot_cache_idx == _hot_cache_size) _hot_cache_idx = 0; _n_hot++; + + if (res != NULL) { + // Even though the region containg res was not in the young list + // when it was recorded in the hot cache it could have been added + // to the free list and subsequently added to the young list in + // the intervening time. If res is in a young region, return NULL + // so that res is not cleaned. See CR 6817995. + + if (is_young_card(res)) { + res = NULL; + } + } + return res; } - void ConcurrentG1Refine::clean_up_cache(int worker_i, G1RemSet* g1rs) { assert(!use_cache(), "cache should be disabled"); - int start_ind = _hot_cache_idx-1; - for (int i = 0; i < _n_hot; i++) { - int ind = start_ind - i; - if (ind < 0) ind = ind + _hot_cache_size; - jbyte* entry = _hot_cache[ind]; - if (entry != NULL) { - g1rs->concurrentRefineOneCard(entry, worker_i); - } - } - _n_hot = 0; - _hot_cache_idx = 0; -} + int start_idx; + + while ((start_idx = _hot_cache_par_claimed_idx) < _n_hot) { // read once + int end_idx = start_idx + _hot_cache_par_chunk_size; -void ConcurrentG1Refine::clear_and_record_card_counts() { - if (G1ConcRSLogCacheSize == 0 && !G1ConcRSCountTraversals) return; - _n_periods++; - if (G1ConcRSCountTraversals) { - for (size_t i = 0; i < _n_card_counts; i++) { - unsigned char bucket = _card_counts[i]; - _cur_card_count_histo[bucket]++; - _card_counts[i] = 0; - } - gclog_or_tty->print_cr("Card counts:"); - for (int i = 0; i < 256; i++) { - if (_cur_card_count_histo[i] > 0) { - gclog_or_tty->print_cr(" %3d: %9d", i, _cur_card_count_histo[i]); - _cum_card_count_histo[i] += _cur_card_count_histo[i]; - _cur_card_count_histo[i] = 0; + if (start_idx == + Atomic::cmpxchg(end_idx, &_hot_cache_par_claimed_idx, start_idx)) { + // The current worker has successfully claimed the chunk [start_idx..end_idx) + end_idx = MIN2(end_idx, _n_hot); + for (int i = start_idx; i < end_idx; i++) { + jbyte* entry = _hot_cache[i]; + if (entry != NULL) { + g1rs->concurrentRefineOneCard(entry, worker_i); + } } } - } else { - assert(G1ConcRSLogCacheSize > 0, "Logic"); - Copy::fill_to_words((HeapWord*)(&_card_counts[0]), - _n_card_counts / HeapWordSize); } } -void -ConcurrentG1Refine:: -print_card_count_histo_range(unsigned* histo, int from, int to, - float& cum_card_pct, - float& cum_travs_pct) { - unsigned cards = 0; - unsigned travs = 0; - guarantee(to <= 256, "Precondition"); - for (int i = from; i < to-1; i++) { - cards += histo[i]; - travs += histo[i] * i; - } - if (to == 256) { - unsigned histo_card_sum = 0; - unsigned histo_trav_sum = 0; - for (int i = 1; i < 255; i++) { - histo_trav_sum += histo[i] * i; - } - cards += histo[255]; - // correct traversals for the last one. - unsigned travs_255 = (unsigned) (_total_travs - histo_trav_sum); - travs += travs_255; +void ConcurrentG1Refine::expand_card_count_cache() { + if (_n_card_counts < _max_n_card_counts) { + int new_idx = _cache_size_index+1; + int new_size = _cc_cache_sizes[new_idx]; + if (new_size < 0) new_size = _max_n_card_counts; + + // Make sure we don't go bigger than we will ever need + new_size = MIN2((unsigned) new_size, _max_n_card_counts); - } else { - cards += histo[to-1]; - travs += histo[to-1] * (to-1); - } - float fperiods = (float)_n_periods; - float f_tot_cards = (float)_total_cards/fperiods; - float f_tot_travs = (float)_total_travs/fperiods; - if (cards > 0) { - float fcards = (float)cards/fperiods; - float ftravs = (float)travs/fperiods; - if (to == 256) { - gclog_or_tty->print(" %4d- %10.2f%10.2f", from, fcards, ftravs); - } else { - gclog_or_tty->print(" %4d-%4d %10.2f%10.2f", from, to-1, fcards, ftravs); + // Expand the card count and card epoch tables + if (new_size > (int)_n_card_counts) { + // We can just free and allocate a new array as we're + // not interested in preserving the contents + assert(_card_counts != NULL, "Logic!"); + assert(_card_epochs != NULL, "Logic!"); + FREE_C_HEAP_ARRAY(CardCountCacheEntry, _card_counts); + FREE_C_HEAP_ARRAY(CardEpochCacheEntry, _card_epochs); + _n_card_counts = new_size; + _card_counts = NEW_C_HEAP_ARRAY(CardCountCacheEntry, _n_card_counts); + _card_epochs = NEW_C_HEAP_ARRAY(CardEpochCacheEntry, _n_card_counts); + _cache_size_index = new_idx; } - float pct_cards = fcards*100.0/f_tot_cards; - cum_card_pct += pct_cards; - float pct_travs = ftravs*100.0/f_tot_travs; - cum_travs_pct += pct_travs; - gclog_or_tty->print_cr("%10.2f%10.2f%10.2f%10.2f", - pct_cards, cum_card_pct, - pct_travs, cum_travs_pct); } } -void ConcurrentG1Refine::print_final_card_counts() { - if (!G1ConcRSCountTraversals) return; +void ConcurrentG1Refine::clear_and_record_card_counts() { + if (G1ConcRSLogCacheSize == 0) return; - gclog_or_tty->print_cr("Did %d total traversals of %d distinct cards.", - _total_travs, _total_cards); - float fperiods = (float)_n_periods; - gclog_or_tty->print_cr(" This is an average of %8.2f traversals, %8.2f cards, " - "per collection.", (float)_total_travs/fperiods, - (float)_total_cards/fperiods); - gclog_or_tty->print_cr(" This is an average of %8.2f traversals/distinct " - "dirty card.\n", - _total_cards > 0 ? - (float)_total_travs/(float)_total_cards : 0.0); - +#ifndef PRODUCT + double start = os::elapsedTime(); +#endif - gclog_or_tty->print_cr("Histogram:\n\n%10s %10s%10s%10s%10s%10s%10s", - "range", "# cards", "# travs", "% cards", "(cum)", - "% travs", "(cum)"); - gclog_or_tty->print_cr("------------------------------------------------------------" - "-------------"); - float cum_cards_pct = 0.0; - float cum_travs_pct = 0.0; - for (int i = 1; i < 10; i++) { - print_card_count_histo_range(_cum_card_count_histo, i, i+1, - cum_cards_pct, cum_travs_pct); + if (_expand_card_counts) { + expand_card_count_cache(); + _expand_card_counts = false; + // Only need to clear the epochs. + Copy::fill_to_bytes(&_card_epochs[0], _n_card_counts * sizeof(CardEpochCacheEntry)); } - for (int i = 10; i < 100; i += 10) { - print_card_count_histo_range(_cum_card_count_histo, i, i+10, - cum_cards_pct, cum_travs_pct); - } - print_card_count_histo_range(_cum_card_count_histo, 100, 150, - cum_cards_pct, cum_travs_pct); - print_card_count_histo_range(_cum_card_count_histo, 150, 200, - cum_cards_pct, cum_travs_pct); - print_card_count_histo_range(_cum_card_count_histo, 150, 255, - cum_cards_pct, cum_travs_pct); - print_card_count_histo_range(_cum_card_count_histo, 255, 256, - cum_cards_pct, cum_travs_pct); + + int this_epoch = (int) _n_periods; + assert((this_epoch+1) <= max_jint, "to many periods"); + // Update epoch + _n_periods++; + +#ifndef PRODUCT + double elapsed = os::elapsedTime() - start; + _g1h->g1_policy()->record_cc_clear_time(elapsed * 1000.0); +#endif } diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -29,29 +29,117 @@ class ConcurrentG1Refine: public CHeapObj { ConcurrentG1RefineThread** _threads; int _n_threads; + // The cache for card refinement. - bool _use_cache; - bool _def_use_cache; - size_t _n_periods; - size_t _total_cards; - size_t _total_travs; + bool _use_cache; + bool _def_use_cache; + + size_t _n_periods; // Used as clearing epoch + + // An evicting cache of the number of times each card + // is accessed. Reduces, but does not eliminate, the amount + // of duplicated processing of dirty cards. + + enum SomePrivateConstants { + epoch_bits = 32, + card_num_shift = epoch_bits, + epoch_mask = AllBits, + card_num_mask = AllBits, + + // The initial cache size is approximately this fraction + // of a maximal cache (i.e. the size needed for all cards + // in the heap) + InitialCacheFraction = 512 + }; + + const static julong card_num_mask_in_place = + (julong) card_num_mask << card_num_shift; + + typedef struct { + julong _value; // | card_num | epoch | + } CardEpochCacheEntry; + + julong make_epoch_entry(unsigned int card_num, unsigned int epoch) { + assert(0 <= card_num && card_num < _max_n_card_counts, "Bounds"); + assert(0 <= epoch && epoch <= _n_periods, "must be"); + + return ((julong) card_num << card_num_shift) | epoch; + } + + unsigned int extract_epoch(julong v) { + return (v & epoch_mask); + } + + unsigned int extract_card_num(julong v) { + return (v & card_num_mask_in_place) >> card_num_shift; + } + + typedef struct { + unsigned char _count; + unsigned char _evict_count; + } CardCountCacheEntry; - unsigned char* _card_counts; + CardCountCacheEntry* _card_counts; + CardEpochCacheEntry* _card_epochs; + + // The current number of buckets in the card count cache unsigned _n_card_counts; + + // The max number of buckets required for the number of + // cards for the entire reserved heap + unsigned _max_n_card_counts; + + // Possible sizes of the cache: odd primes that roughly double in size. + // (See jvmtiTagMap.cpp). + static int _cc_cache_sizes[]; + + // The index in _cc_cache_sizes corresponding to the size of + // _card_counts. + int _cache_size_index; + + bool _expand_card_counts; + const jbyte* _ct_bot; - unsigned* _cur_card_count_histo; - unsigned* _cum_card_count_histo; - jbyte** _hot_cache; - int _hot_cache_size; - int _n_hot; - int _hot_cache_idx; + + jbyte** _hot_cache; + int _hot_cache_size; + int _n_hot; + int _hot_cache_idx; + + int _hot_cache_par_chunk_size; + volatile int _hot_cache_par_claimed_idx; + + // Needed to workaround 6817995 + CardTableModRefBS* _ct_bs; + G1CollectedHeap* _g1h; + + // Expands the array that holds the card counts to the next size up + void expand_card_count_cache(); + + // hash a given key (index of card_ptr) with the specified size + static unsigned int hash(size_t key, int size) { + return (unsigned int) key % size; + } + + // hash a given key (index of card_ptr) + unsigned int hash(size_t key) { + return hash(key, _n_card_counts); + } + + unsigned ptr_2_card_num(jbyte* card_ptr) { + return (unsigned) (card_ptr - _ct_bot); + } + + jbyte* card_num_2_ptr(unsigned card_num) { + return (jbyte*) (_ct_bot + card_num); + } // Returns the count of this card after incrementing it. - int add_card_count(jbyte* card_ptr); + jbyte* add_card_count(jbyte* card_ptr, int* count, bool* defer); - void print_card_count_histo_range(unsigned* histo, int from, int to, - float& cum_card_pct, - float& cum_travs_pct); + // Returns true if this card is in a young region + bool is_young_card(jbyte* card_ptr); + public: ConcurrentG1Refine(); ~ConcurrentG1Refine(); @@ -65,11 +153,16 @@ // If this is the first entry for the slot, writes into the cache and // returns NULL. If it causes an eviction, returns the evicted pointer. // Otherwise, its a cache hit, and returns NULL. - jbyte* cache_insert(jbyte* card_ptr); + jbyte* cache_insert(jbyte* card_ptr, bool* defer); // Process the cached entries. void clean_up_cache(int worker_i, G1RemSet* g1rs); + // Set up for parallel processing of the cards in the hot cache + void clear_hot_cache_claimed_index() { + _hot_cache_par_claimed_idx = 0; + } + // Discard entries in the hot cache. void clear_hot_cache() { _hot_cache_idx = 0; _n_hot = 0; @@ -84,7 +177,6 @@ } void clear_and_record_card_counts(); - void print_final_card_counts(); static size_t thread_num(); }; diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -104,17 +104,17 @@ double start_vtime_sec; // only used when G1SmoothConcRefine is on int prev_buffer_num; // only used when G1SmoothConcRefine is on // This thread activation threshold - int threshold = DCQBarrierProcessCompletedThreshold * _worker_id; + int threshold = G1UpdateBufferQueueProcessingThreshold * _worker_id; // Next thread activation threshold - int next_threshold = threshold + DCQBarrierProcessCompletedThreshold; - int deactivation_threshold = MAX2(threshold - DCQBarrierProcessCompletedThreshold / 2, 0); + int next_threshold = threshold + G1UpdateBufferQueueProcessingThreshold; + int deactivation_threshold = MAX2(threshold - G1UpdateBufferQueueProcessingThreshold / 2, 0); if (G1SmoothConcRefine) { lower_limit = 0; start_vtime_sec = os::elapsedVTime(); prev_buffer_num = (int) dcqs.completed_buffers_num(); } else { - lower_limit = DCQBarrierProcessCompletedThreshold / 4; // For now. + lower_limit = G1UpdateBufferQueueProcessingThreshold / 4; // For now. } while (dcqs.apply_closure_to_completed_buffer(_worker_id + _worker_id_offset, lower_limit)) { double end_vtime_sec; diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -2401,7 +2401,7 @@ // Now process this portion of this one. int lim = MIN2(next_arr_ind, len); for (int j = arr_ind; j < lim; j++) { - do_oop(aobj->obj_at_addr(j)); + do_oop(aobj->objArrayOopDesc::obj_at_addr(j)); } } else { diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -80,8 +80,8 @@ int max_completed_queue, Mutex* lock, PtrQueueSet* fl_owner) { PtrQueueSet::initialize(cbl_mon, fl_lock, max_completed_queue, fl_owner); - set_buffer_size(DCQBarrierQueueBufferSize); - set_process_completed_threshold(DCQBarrierProcessCompletedThreshold); + set_buffer_size(G1UpdateBufferSize); + set_process_completed_threshold(G1UpdateBufferQueueProcessingThreshold); _shared_dirty_card_queue.set_lock(lock); _free_ids = new FreeIdSet((int) num_par_ids(), _cbl_mon); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -1591,7 +1591,7 @@ JavaThread::dirty_card_queue_set().initialize(DirtyCardQ_CBL_mon, DirtyCardQ_FL_lock, - G1DirtyCardQueueMax, + G1UpdateBufferQueueMaxLength, Shared_DirtyCardQ_lock); if (G1DeferredRSUpdate) { @@ -1637,6 +1637,9 @@ void G1CollectedHeap::iterate_dirty_card_closure(bool concurrent, int worker_i) { + // Clean cards in the hot card cache + concurrent_g1_refine()->clean_up_cache(worker_i, g1_rem_set()); + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); int n_completed_buffers = 0; while (dcqs.apply_closure_to_completed_buffer(worker_i, 0, true)) { @@ -1645,9 +1648,6 @@ g1_policy()->record_update_rs_processed_buffers(worker_i, (double) n_completed_buffers); dcqs.clear_n_completed_buffers(); - // Finish up the queue... - if (worker_i == 0) concurrent_g1_refine()->clean_up_cache(worker_i, - g1_rem_set()); assert(!dcqs.completed_buffers_exist_dirty(), "Completed buffers exist!"); } @@ -2414,8 +2414,6 @@ } void G1CollectedHeap::print_tracing_info() const { - concurrent_g1_refine()->print_final_card_counts(); - // We'll overload this to mean "trace GC pause statistics." if (TraceGen0Time || TraceGen1Time) { // The "G1CollectorPolicy" is keeping track of these stats, so delegate @@ -2845,6 +2843,11 @@ if (PrintHeapAtGC) { Universe::print_heap_after_gc(); } + if (G1SummarizeRSetStats && + (G1SummarizeRSetStatsPeriod > 0) && + (total_collections() % G1SummarizeRSetStatsPeriod == 0)) { + g1_rem_set()->print_summary_info(); + } } void G1CollectedHeap::set_gc_alloc_region(int purpose, HeapRegion* r) { @@ -4106,6 +4109,8 @@ g1_rem_set()->prepare_for_oops_into_collection_set_do(); concurrent_g1_refine()->set_use_cache(false); + concurrent_g1_refine()->clear_hot_cache_claimed_index(); + int n_workers = (ParallelGCThreads > 0 ? workers()->total_workers() : 1); set_par_threads(n_workers); G1ParTask g1_par_task(this, n_workers, _task_queues); @@ -4138,6 +4143,7 @@ } g1_rem_set()->cleanup_after_oops_into_collection_set_do(); + concurrent_g1_refine()->clear_hot_cache(); concurrent_g1_refine()->set_use_cache(true); finalize_for_evac_failure(); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -94,7 +94,14 @@ _summary(new Summary()), _abandoned_summary(new AbandonedSummary()), +#ifndef PRODUCT _cur_clear_ct_time_ms(0.0), + _min_clear_cc_time_ms(-1.0), + _max_clear_cc_time_ms(-1.0), + _cur_clear_cc_time_ms(0.0), + _cum_clear_cc_time_ms(0.0), + _num_cc_clears(0L), +#endif _region_num_young(0), _region_num_tenured(0), @@ -1648,6 +1655,15 @@ print_stats(1, "Object Copying", obj_copy_time); } } +#ifndef PRODUCT + print_stats(1, "Cur Clear CC", _cur_clear_cc_time_ms); + print_stats(1, "Cum Clear CC", _cum_clear_cc_time_ms); + print_stats(1, "Min Clear CC", _min_clear_cc_time_ms); + print_stats(1, "Max Clear CC", _max_clear_cc_time_ms); + if (_num_cc_clears > 0) { + print_stats(1, "Avg Clear CC", _cum_clear_cc_time_ms / ((double)_num_cc_clears)); + } +#endif print_stats(1, "Other", other_time_ms); for (int i = 0; i < _aux_num; ++i) { if (_cur_aux_times_set[i]) { diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -112,7 +112,6 @@ return 8*M; } - double _cur_collection_start_sec; size_t _cur_collection_pause_used_at_start_bytes; size_t _cur_collection_pause_used_regions_at_start; @@ -122,6 +121,15 @@ double _cur_clear_ct_time_ms; bool _satb_drain_time_set; +#ifndef PRODUCT + // Card Table Count Cache stats + double _min_clear_cc_time_ms; // min + double _max_clear_cc_time_ms; // max + double _cur_clear_cc_time_ms; // clearing time during current pause + double _cum_clear_cc_time_ms; // cummulative clearing time + jlong _num_cc_clears; // number of times the card count cache has been cleared +#endif + double _cur_CH_strong_roots_end_sec; double _cur_CH_strong_roots_dur_ms; double _cur_G1_strong_roots_end_sec; @@ -931,6 +939,18 @@ _cur_aux_times_ms[i] += ms; } +#ifndef PRODUCT + void record_cc_clear_time(double ms) { + if (_min_clear_cc_time_ms < 0.0 || ms <= _min_clear_cc_time_ms) + _min_clear_cc_time_ms = ms; + if (_max_clear_cc_time_ms < 0.0 || ms >= _max_clear_cc_time_ms) + _max_clear_cc_time_ms = ms; + _cur_clear_cc_time_ms = ms; + _cum_clear_cc_time_ms += ms; + _num_cc_clears++; + } +#endif + // Record the fact that "bytes" bytes allocated in a region. void record_before_bytes(size_t bytes); void record_after_bytes(size_t bytes); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -676,6 +676,55 @@ static IntHistogram out_of_histo(50, 50); +void HRInto_G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i) { + // Construct the region representing the card. + HeapWord* start = _ct_bs->addr_for(card_ptr); + // And find the region containing it. + HeapRegion* r = _g1->heap_region_containing(start); + assert(r != NULL, "unexpected null"); + + HeapWord* end = _ct_bs->addr_for(card_ptr + 1); + MemRegion dirtyRegion(start, end); + +#if CARD_REPEAT_HISTO + init_ct_freq_table(_g1->g1_reserved_obj_bytes()); + ct_freq_note_card(_ct_bs->index_for(start)); +#endif + + UpdateRSOopClosure update_rs_oop_cl(this, worker_i); + update_rs_oop_cl.set_from(r); + FilterOutOfRegionClosure filter_then_update_rs_oop_cl(r, &update_rs_oop_cl); + + // Undirty the card. + *card_ptr = CardTableModRefBS::clean_card_val(); + // We must complete this write before we do any of the reads below. + OrderAccess::storeload(); + // And process it, being careful of unallocated portions of TLAB's. + HeapWord* stop_point = + r->oops_on_card_seq_iterate_careful(dirtyRegion, + &filter_then_update_rs_oop_cl); + // If stop_point is non-null, then we encountered an unallocated region + // (perhaps the unfilled portion of a TLAB.) For now, we'll dirty the + // card and re-enqueue: if we put off the card until a GC pause, then the + // unallocated portion will be filled in. Alternatively, we might try + // the full complexity of the technique used in "regular" precleaning. + if (stop_point != NULL) { + // The card might have gotten re-dirtied and re-enqueued while we + // worked. (In fact, it's pretty likely.) + if (*card_ptr != CardTableModRefBS::dirty_card_val()) { + *card_ptr = CardTableModRefBS::dirty_card_val(); + MutexLockerEx x(Shared_DirtyCardQ_lock, + Mutex::_no_safepoint_check_flag); + DirtyCardQueue* sdcq = + JavaThread::dirty_card_queue_set().shared_dirty_card_queue(); + sdcq->enqueue(card_ptr); + } + } else { + out_of_histo.add_entry(filter_then_update_rs_oop_cl.out_of_region()); + _conc_refine_cards++; + } +} + void HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i) { // If the card is no longer dirty, nothing to do. if (*card_ptr != CardTableModRefBS::dirty_card_val()) return; @@ -716,61 +765,63 @@ return; } - // Should we defer it? - if (_cg1r->use_cache()) { - card_ptr = _cg1r->cache_insert(card_ptr); - // If it was not an eviction, nothing to do. - if (card_ptr == NULL) return; + // Should we defer processing the card? + // + // Previously the result from the insert_cache call would be + // either card_ptr (implying that card_ptr was currently "cold"), + // null (meaning we had inserted the card ptr into the "hot" + // cache, which had some headroom), or a "hot" card ptr + // extracted from the "hot" cache. + // + // Now that the _card_counts cache in the ConcurrentG1Refine + // instance is an evicting hash table, the result we get back + // could be from evicting the card ptr in an already occupied + // bucket (in which case we have replaced the card ptr in the + // bucket with card_ptr and "defer" is set to false). To avoid + // having a data structure (updates to which would need a lock) + // to hold these unprocessed dirty cards, we need to immediately + // process card_ptr. The actions needed to be taken on return + // from cache_insert are summarized in the following table: + // + // res defer action + // -------------------------------------------------------------- + // null false card evicted from _card_counts & replaced with + // card_ptr; evicted ptr added to hot cache. + // No need to process res; immediately process card_ptr + // + // null true card not evicted from _card_counts; card_ptr added + // to hot cache. + // Nothing to do. + // + // non-null false card evicted from _card_counts & replaced with + // card_ptr; evicted ptr is currently "cold" or + // caused an eviction from the hot cache. + // Immediately process res; process card_ptr. + // + // non-null true card not evicted from _card_counts; card_ptr is + // currently cold, or caused an eviction from hot + // cache. + // Immediately process res; no need to process card_ptr. - // OK, we have to reset the card start, region, etc. - start = _ct_bs->addr_for(card_ptr); - r = _g1->heap_region_containing(start); - if (r == NULL) { - guarantee(_g1->is_in_permanent(start), "Or else where?"); - return; // Not in the G1 heap (might be in perm, for example.) + jbyte* res = card_ptr; + bool defer = false; + if (_cg1r->use_cache()) { + jbyte* res = _cg1r->cache_insert(card_ptr, &defer); + if (res != NULL && (res != card_ptr || defer)) { + start = _ct_bs->addr_for(res); + r = _g1->heap_region_containing(start); + if (r == NULL) { + assert(_g1->is_in_permanent(start), "Or else where?"); + } else { + guarantee(!r->is_young(), "It was evicted in the current minor cycle."); + // Process card pointer we get back from the hot card cache + concurrentRefineOneCard_impl(res, worker_i); + } } - guarantee(!r->is_young(), "It was evicted in the current minor cycle."); } - HeapWord* end = _ct_bs->addr_for(card_ptr + 1); - MemRegion dirtyRegion(start, end); - -#if CARD_REPEAT_HISTO - init_ct_freq_table(_g1->g1_reserved_obj_bytes()); - ct_freq_note_card(_ct_bs->index_for(start)); -#endif - - UpdateRSOopClosure update_rs_oop_cl(this, worker_i); - update_rs_oop_cl.set_from(r); - FilterOutOfRegionClosure filter_then_update_rs_oop_cl(r, &update_rs_oop_cl); - - // Undirty the card. - *card_ptr = CardTableModRefBS::clean_card_val(); - // We must complete this write before we do any of the reads below. - OrderAccess::storeload(); - // And process it, being careful of unallocated portions of TLAB's. - HeapWord* stop_point = - r->oops_on_card_seq_iterate_careful(dirtyRegion, - &filter_then_update_rs_oop_cl); - // If stop_point is non-null, then we encountered an unallocated region - // (perhaps the unfilled portion of a TLAB.) For now, we'll dirty the - // card and re-enqueue: if we put off the card until a GC pause, then the - // unallocated portion will be filled in. Alternatively, we might try - // the full complexity of the technique used in "regular" precleaning. - if (stop_point != NULL) { - // The card might have gotten re-dirtied and re-enqueued while we - // worked. (In fact, it's pretty likely.) - if (*card_ptr != CardTableModRefBS::dirty_card_val()) { - *card_ptr = CardTableModRefBS::dirty_card_val(); - MutexLockerEx x(Shared_DirtyCardQ_lock, - Mutex::_no_safepoint_check_flag); - DirtyCardQueue* sdcq = - JavaThread::dirty_card_queue_set().shared_dirty_card_queue(); - sdcq->enqueue(card_ptr); - } - } else { - out_of_histo.add_entry(filter_then_update_rs_oop_cl.out_of_region()); - _conc_refine_cards++; + if (!defer) { + concurrentRefineOneCard_impl(card_ptr, worker_i); } } diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -157,6 +157,10 @@ } } + // The routine that performs the actual work of refining a dirty + // card. + void concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i); + protected: template void write_ref_nv(HeapRegion* from, T* p); template void par_write_ref_nv(HeapRegion* from, T* p, int tid); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -34,7 +34,7 @@ product(intx, G1ConfidencePercent, 50, \ "Confidence level for MMU/pause predictions") \ \ - develop(intx, G1MarkingOverheadPercent, 0, \ + develop(intx, G1MarkingOverheadPercent, 0, \ "Overhead of concurrent marking") \ \ develop(bool, G1AccountConcurrentOverhead, false, \ @@ -47,7 +47,7 @@ develop(bool, G1Gen, true, \ "If true, it will enable the generational G1") \ \ - develop(intx, G1GCPercent, 10, \ + develop(intx, G1GCPercent, 10, \ "The desired percent time spent on GC") \ \ develop(intx, G1PolicyVerbose, 0, \ @@ -74,6 +74,12 @@ diagnostic(bool, G1SummarizeRSetStats, false, \ "Summarize remembered set processing info") \ \ + diagnostic(intx, G1SummarizeRSetStatsPeriod, 0, \ + "The period (in number of GCs) at which we will generate " \ + "update buffer processing info " \ + "(0 means do not periodically generate this info); " \ + "it also requires -XX:+G1SummarizeRSetStats") \ + \ diagnostic(bool, G1SummarizeZFStats, false, \ "Summarize zero-filling info") \ \ @@ -167,17 +173,20 @@ develop(bool, G1DisablePostBarrier, false, \ "Disable generation of post-barrier (i.e., RS barrier) ") \ \ - product(intx, G1DirtyCardQueueMax, 30, \ - "Maximum number of completed RS buffers before mutator threads " \ - "start processing them.") \ + product(intx, G1UpdateBufferSize, 256, \ + "Size of an update buffer") \ + \ + product(intx, G1UpdateBufferQueueProcessingThreshold, 5, \ + "Number of enqueued update buffers that will " \ + "trigger concurrent processing") \ + \ + product(intx, G1UpdateBufferQueueMaxLength, 30, \ + "Maximum number of enqueued update buffers before mutator " \ + "threads start processing new ones instead of enqueueing them") \ \ develop(intx, G1ConcRSLogCacheSize, 10, \ "Log base 2 of the length of conc RS hot-card cache.") \ \ - develop(bool, G1ConcRSCountTraversals, false, \ - "If true, gather data about the number of times CR traverses " \ - "cards ") \ - \ develop(intx, G1ConcRSHotCardLimit, 4, \ "The threshold that defines (>=) a hot card.") \ \ @@ -251,6 +260,10 @@ \ product(uintx, G1ParallelRSetThreads, 0, \ "If non-0 is the number of parallel rem set update threads, " \ - "otherwise the value is determined ergonomically.") + "otherwise the value is determined ergonomically.") \ + \ + develop(intx, G1CardCountCacheExpandThreshold, 16, \ + "Expand the card count cache if the number of collisions for " \ + "a particular entry exceeds this value.") G1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG, DECLARE_MANAGEABLE_FLAG, DECLARE_PRODUCT_RW_FLAG) diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 --- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 Wed Jul 05 16:59:43 2017 +0200 @@ -45,11 +45,14 @@ concurrentG1Refine.cpp concurrentG1RefineThread.hpp concurrentG1Refine.cpp copy.hpp concurrentG1Refine.cpp g1CollectedHeap.inline.hpp +concurrentG1Refine.cpp g1CollectorPolicy.hpp concurrentG1Refine.cpp g1RemSet.hpp concurrentG1Refine.cpp space.inline.hpp +concurrentG1Refine.cpp heapRegionSeq.inline.hpp concurrentG1Refine.hpp globalDefinitions.hpp concurrentG1Refine.hpp allocation.hpp +concurrentG1Refine.hpp cardTableModRefBS.hpp concurrentG1Refine.hpp thread.hpp concurrentG1RefineThread.cpp concurrentG1Refine.hpp diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/includeDB_core --- a/hotspot/src/share/vm/includeDB_core Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/includeDB_core Wed Jul 05 16:59:43 2017 +0200 @@ -872,6 +872,7 @@ classFileParser.cpp symbolOop.hpp classFileParser.cpp symbolTable.hpp classFileParser.cpp systemDictionary.hpp +classFileParser.cpp threadService.hpp classFileParser.cpp timer.hpp classFileParser.cpp universe.inline.hpp classFileParser.cpp verificationType.hpp @@ -924,6 +925,7 @@ classLoader.cpp symbolOop.hpp classLoader.cpp systemDictionary.hpp classLoader.cpp threadCritical.hpp +classLoader.cpp threadService.hpp classLoader.cpp timer.hpp classLoader.cpp universe.inline.hpp classLoader.cpp vmSymbols.hpp @@ -4019,6 +4021,7 @@ systemDictionary.cpp resolutionErrors.hpp systemDictionary.cpp signature.hpp systemDictionary.cpp systemDictionary.hpp +systemDictionary.cpp threadService.hpp systemDictionary.cpp typeArrayKlass.hpp systemDictionary.cpp vmSymbols.hpp diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/interpreter/abstractInterpreter.hpp --- a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -122,11 +122,15 @@ static int size_top_interpreter_activation(methodOop method); // Deoptimization support - static address continuation_for(methodOop method, - address bcp, - int callee_parameters, - bool is_top_frame, - bool& use_next_mdp); + // Compute the entry address for continuation after + static address deopt_continue_after_entry(methodOop method, + address bcp, + int callee_parameters, + bool is_top_frame); + // Compute the entry address for reexecution + static address deopt_reexecute_entry(methodOop method, address bcp); + // Deoptimization should reexecute this bytecode + static bool bytecode_should_reexecute(Bytecodes::Code code); // share implementation of size_activation and layout_activation: static int size_activation(methodOop method, diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/interpreter/interpreter.cpp --- a/hotspot/src/share/vm/interpreter/interpreter.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/interpreter/interpreter.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -284,76 +284,19 @@ //------------------------------------------------------------------------------------------------------------------------ // Deoptimization support -// If deoptimization happens, this method returns the point where to continue in -// interpreter. For calls (invokexxxx, newxxxx) the continuation is at next -// bci and the top of stack is in eax/edx/FPU tos. -// For putfield/getfield, put/getstatic, the continuation is at the same -// bci and the TOS is on stack. - -// Note: deopt_entry(type, 0) means reexecute bytecode -// deopt_entry(type, length) means continue at next bytecode - -address AbstractInterpreter::continuation_for(methodOop method, address bcp, int callee_parameters, bool is_top_frame, bool& use_next_mdp) { +// If deoptimization happens, this function returns the point of next bytecode to continue execution +address AbstractInterpreter::deopt_continue_after_entry(methodOop method, address bcp, int callee_parameters, bool is_top_frame) { assert(method->contains(bcp), "just checkin'"); Bytecodes::Code code = Bytecodes::java_code_at(bcp); + assert(!Interpreter::bytecode_should_reexecute(code), "should not reexecute"); int bci = method->bci_from(bcp); int length = -1; // initial value for debugging // compute continuation length length = Bytecodes::length_at(bcp); // compute result type BasicType type = T_ILLEGAL; - // when continuing after a compiler safepoint, re-execute the bytecode - // (an invoke is continued after the safepoint) - use_next_mdp = true; + switch (code) { - case Bytecodes::_lookupswitch: - case Bytecodes::_tableswitch: - case Bytecodes::_fast_binaryswitch: - case Bytecodes::_fast_linearswitch: - // recompute condtional expression folded into _if - case Bytecodes::_lcmp : - case Bytecodes::_fcmpl : - case Bytecodes::_fcmpg : - case Bytecodes::_dcmpl : - case Bytecodes::_dcmpg : - case Bytecodes::_ifnull : - case Bytecodes::_ifnonnull : - case Bytecodes::_goto : - case Bytecodes::_goto_w : - case Bytecodes::_ifeq : - case Bytecodes::_ifne : - case Bytecodes::_iflt : - case Bytecodes::_ifge : - case Bytecodes::_ifgt : - case Bytecodes::_ifle : - case Bytecodes::_if_icmpeq : - case Bytecodes::_if_icmpne : - case Bytecodes::_if_icmplt : - case Bytecodes::_if_icmpge : - case Bytecodes::_if_icmpgt : - case Bytecodes::_if_icmple : - case Bytecodes::_if_acmpeq : - case Bytecodes::_if_acmpne : - // special cases - case Bytecodes::_getfield : - case Bytecodes::_putfield : - case Bytecodes::_getstatic : - case Bytecodes::_putstatic : - case Bytecodes::_aastore : - // reexecute the operation and TOS value is on stack - assert(is_top_frame, "must be top frame"); - use_next_mdp = false; - return Interpreter::deopt_entry(vtos, 0); - break; - -#ifdef COMPILER1 - case Bytecodes::_athrow : - assert(is_top_frame, "must be top frame"); - use_next_mdp = false; - return Interpreter::rethrow_exception_entry(); - break; -#endif /* COMPILER1 */ - case Bytecodes::_invokevirtual : case Bytecodes::_invokespecial : case Bytecodes::_invokestatic : @@ -392,6 +335,70 @@ : Interpreter::return_entry(as_TosState(type), length); } +// If deoptimization happens, this function returns the point where the interpreter reexecutes +// the bytecode. +// Note: Bytecodes::_athrow is a special case in that it does not return +// Interpreter::deopt_entry(vtos, 0) like others +address AbstractInterpreter::deopt_reexecute_entry(methodOop method, address bcp) { + assert(method->contains(bcp), "just checkin'"); + Bytecodes::Code code = Bytecodes::java_code_at(bcp); +#ifdef COMPILER1 + if(code == Bytecodes::_athrow ) { + return Interpreter::rethrow_exception_entry(); + } +#endif /* COMPILER1 */ + return Interpreter::deopt_entry(vtos, 0); +} + +// If deoptimization happens, the interpreter should reexecute these bytecodes. +// This function mainly helps the compilers to set up the reexecute bit. +bool AbstractInterpreter::bytecode_should_reexecute(Bytecodes::Code code) { + switch (code) { + case Bytecodes::_lookupswitch: + case Bytecodes::_tableswitch: + case Bytecodes::_fast_binaryswitch: + case Bytecodes::_fast_linearswitch: + // recompute condtional expression folded into _if + case Bytecodes::_lcmp : + case Bytecodes::_fcmpl : + case Bytecodes::_fcmpg : + case Bytecodes::_dcmpl : + case Bytecodes::_dcmpg : + case Bytecodes::_ifnull : + case Bytecodes::_ifnonnull : + case Bytecodes::_goto : + case Bytecodes::_goto_w : + case Bytecodes::_ifeq : + case Bytecodes::_ifne : + case Bytecodes::_iflt : + case Bytecodes::_ifge : + case Bytecodes::_ifgt : + case Bytecodes::_ifle : + case Bytecodes::_if_icmpeq : + case Bytecodes::_if_icmpne : + case Bytecodes::_if_icmplt : + case Bytecodes::_if_icmpge : + case Bytecodes::_if_icmpgt : + case Bytecodes::_if_icmple : + case Bytecodes::_if_acmpeq : + case Bytecodes::_if_acmpne : + // special cases + case Bytecodes::_getfield : + case Bytecodes::_putfield : + case Bytecodes::_getstatic : + case Bytecodes::_putstatic : + case Bytecodes::_aastore : +#ifdef COMPILER1 + //special case of reexecution + case Bytecodes::_athrow : +#endif + return true; + + default: + return false; + } +} + void AbstractInterpreterGenerator::bang_stack_shadow_pages(bool native_call) { // Quick & dirty stack overflow checking: bang the stack & handle trap. // Note that we do the banging after the frame is setup, since the exception diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/interpreter/templateInterpreter.cpp --- a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -605,28 +605,41 @@ } } -// If deoptimization happens, this method returns the point where to continue in -// interpreter. For calls (invokexxxx, newxxxx) the continuation is at next -// bci and the top of stack is in eax/edx/FPU tos. -// For putfield/getfield, put/getstatic, the continuation is at the same -// bci and the TOS is on stack. +//------------------------------------------------------------------------------------------------------------------------ +// Deoptimization support -// Note: deopt_entry(type, 0) means reexecute bytecode -// deopt_entry(type, length) means continue at next bytecode +// If deoptimization happens, this function returns the point of next bytecode to continue execution +address TemplateInterpreter::deopt_continue_after_entry(methodOop method, address bcp, int callee_parameters, bool is_top_frame) { + return AbstractInterpreter::deopt_continue_after_entry(method, bcp, callee_parameters, is_top_frame); +} -address TemplateInterpreter::continuation_for(methodOop method, address bcp, int callee_parameters, bool is_top_frame, bool& use_next_mdp) { +// If deoptimization happens, this function returns the point where the interpreter reexecutes +// the bytecode. +// Note: Bytecodes::_athrow (C1 only) and Bytecodes::_return are the special cases +// that do not return "Interpreter::deopt_entry(vtos, 0)" +address TemplateInterpreter::deopt_reexecute_entry(methodOop method, address bcp) { assert(method->contains(bcp), "just checkin'"); Bytecodes::Code code = Bytecodes::java_code_at(bcp); if (code == Bytecodes::_return) { - // This is used for deopt during registration of finalizers - // during Object.. We simply need to resume execution at - // the standard return vtos bytecode to pop the frame normally. - // reexecuting the real bytecode would cause double registration - // of the finalizable object. - assert(is_top_frame, "must be on top"); - return _normal_table.entry(Bytecodes::_return).entry(vtos); + // This is used for deopt during registration of finalizers + // during Object.. We simply need to resume execution at + // the standard return vtos bytecode to pop the frame normally. + // reexecuting the real bytecode would cause double registration + // of the finalizable object. + return _normal_table.entry(Bytecodes::_return).entry(vtos); } else { - return AbstractInterpreter::continuation_for(method, bcp, callee_parameters, is_top_frame, use_next_mdp); + return AbstractInterpreter::deopt_reexecute_entry(method, bcp); + } +} + +// If deoptimization happens, the interpreter should reexecute this bytecode. +// This function mainly helps the compilers to set up the reexecute bit. +bool TemplateInterpreter::bytecode_should_reexecute(Bytecodes::Code code) { + if (code == Bytecodes::_return) { + //Yes, we consider Bytecodes::_return as a special case of reexecution + return true; + } else { + return AbstractInterpreter::bytecode_should_reexecute(code); } } diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/interpreter/templateInterpreter.hpp --- a/hotspot/src/share/vm/interpreter/templateInterpreter.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/interpreter/templateInterpreter.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -171,11 +171,15 @@ static void ignore_safepoints(); // ignores safepoints // Deoptimization support - static address continuation_for(methodOop method, - address bcp, - int callee_parameters, - bool is_top_frame, - bool& use_next_mdp); + // Compute the entry address for continuation after + static address deopt_continue_after_entry(methodOop method, + address bcp, + int callee_parameters, + bool is_top_frame); + // Deoptimization should reexecute this bytecode + static bool bytecode_should_reexecute(Bytecodes::Code code); + // Compute the address for reexecution + static address deopt_reexecute_entry(methodOop method, address bcp); #include "incls/_templateInterpreter_pd.hpp.incl" diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/memory/cardTableModRefBS.cpp --- a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -253,8 +253,16 @@ } #endif // The guard page is always committed and should not be committed over. - HeapWord* const new_end_for_commit = MIN2(new_end_aligned, - _guard_region.start()); + // "guarded" is used for assertion checking below and recalls the fact + // that the would-be end of the new committed region would have + // penetrated the guard page. + HeapWord* new_end_for_commit = new_end_aligned; + + DEBUG_ONLY(bool guarded = false;) + if (new_end_for_commit > _guard_region.start()) { + new_end_for_commit = _guard_region.start(); + DEBUG_ONLY(guarded = true;) + } if (new_end_for_commit > cur_committed.end()) { // Must commit new pages. @@ -302,7 +310,7 @@ // not the aligned up expanded region. // jbyte* const end = byte_after(new_region.last()); jbyte* const end = (jbyte*) new_end_for_commit; - assert((end >= byte_after(new_region.last())) || collided, + assert((end >= byte_after(new_region.last())) || collided || guarded, "Expect to be beyond new region unless impacting another region"); // do nothing if we resized downward. #ifdef ASSERT diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/memory/genCollectedHeap.cpp --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -482,6 +482,10 @@ for (int i = starting_level; i <= max_level; i++) { if (_gens[i]->should_collect(full, size, is_tlab)) { if (i == n_gens() - 1) { // a major collection is to happen + if (!complete) { + // The full_collections increment was missed above. + increment_total_full_collections(); + } pre_full_gc_dump(); // do any pre full gc dumps } // Timer for individual generations. Last argument is false: no CR diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/memory/serialize.cpp --- a/hotspot/src/share/vm/memory/serialize.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/memory/serialize.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -51,7 +51,7 @@ soc->do_tag(arrayOopDesc::base_offset_in_bytes(T_BYTE)); soc->do_tag(sizeof(constantPoolOopDesc)); soc->do_tag(sizeof(constantPoolCacheOopDesc)); - soc->do_tag(objArrayOopDesc::base_offset_in_bytes(T_BYTE)); + soc->do_tag(objArrayOopDesc::base_offset_in_bytes()); soc->do_tag(typeArrayOopDesc::base_offset_in_bytes(T_BYTE)); soc->do_tag(sizeof(symbolOopDesc)); soc->do_tag(sizeof(klassOopDesc)); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/oops/arrayKlass.cpp --- a/hotspot/src/share/vm/oops/arrayKlass.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/oops/arrayKlass.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -140,6 +140,7 @@ THROW_0(vmSymbols::java_lang_NegativeArraySizeException()); } if (length > arrayOopDesc::max_array_length(T_ARRAY)) { + report_java_out_of_memory("Requested array size exceeds VM limit"); THROW_OOP_0(Universe::out_of_memory_error_array_size()); } int size = objArrayOopDesc::object_size(length); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/oops/instanceKlass.cpp --- a/hotspot/src/share/vm/oops/instanceKlass.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -158,9 +158,6 @@ // timer handles recursion assert(THREAD->is_Java_thread(), "non-JavaThread in link_class_impl"); JavaThread* jt = (JavaThread*)THREAD; - PerfTraceTimedEvent vmtimer(ClassLoader::perf_class_link_time(), - ClassLoader::perf_classes_linked(), - jt->get_thread_stat()->class_link_recursion_count_addr()); // link super class before linking this class instanceKlassHandle super(THREAD, this_oop->super()); @@ -194,6 +191,15 @@ return true; } + // trace only the link time for this klass that includes + // the verification time + PerfClassTraceTime vmtimer(ClassLoader::perf_class_link_time(), + ClassLoader::perf_class_link_selftime(), + ClassLoader::perf_classes_linked(), + jt->get_thread_stat()->perf_recursion_counts_addr(), + jt->get_thread_stat()->perf_timers_addr(), + PerfClassTraceTime::CLASS_LINK); + // verification & rewriting { ObjectLocker ol(this_oop, THREAD); @@ -203,12 +209,14 @@ if (!this_oop->is_linked()) { if (!this_oop->is_rewritten()) { { - assert(THREAD->is_Java_thread(), "non-JavaThread in link_class_impl"); - JavaThread* jt = (JavaThread*)THREAD; // Timer includes any side effects of class verification (resolution, // etc), but not recursive entry into verify_code(). - PerfTraceTime timer(ClassLoader::perf_class_verify_time(), - jt->get_thread_stat()->class_verify_recursion_count_addr()); + PerfClassTraceTime timer(ClassLoader::perf_class_verify_time(), + ClassLoader::perf_class_verify_selftime(), + ClassLoader::perf_classes_verified(), + jt->get_thread_stat()->perf_recursion_counts_addr(), + jt->get_thread_stat()->perf_timers_addr(), + PerfClassTraceTime::CLASS_VERIFY); bool verify_ok = verify_code(this_oop, throw_verifyerror, THREAD); if (!verify_ok) { return false; @@ -350,9 +358,12 @@ JavaThread* jt = (JavaThread*)THREAD; // Timer includes any side effects of class initialization (resolution, // etc), but not recursive entry into call_class_initializer(). - PerfTraceTimedEvent timer(ClassLoader::perf_class_init_time(), - ClassLoader::perf_classes_inited(), - jt->get_thread_stat()->class_init_recursion_count_addr()); + PerfClassTraceTime timer(ClassLoader::perf_class_init_time(), + ClassLoader::perf_class_init_selftime(), + ClassLoader::perf_classes_inited(), + jt->get_thread_stat()->perf_recursion_counts_addr(), + jt->get_thread_stat()->perf_timers_addr(), + PerfClassTraceTime::CLASS_CLINIT); this_oop->call_class_initializer(THREAD); } @@ -497,6 +508,7 @@ objArrayOop instanceKlass::allocate_objArray(int n, int length, TRAPS) { if (length < 0) THROW_0(vmSymbols::java_lang_NegativeArraySizeException()); if (length > arrayOopDesc::max_array_length(T_OBJECT)) { + report_java_out_of_memory("Requested array size exceeds VM limit"); THROW_OOP_0(Universe::out_of_memory_error_array_size()); } int size = objArrayOopDesc::object_size(length); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/oops/objArrayKlass.cpp --- a/hotspot/src/share/vm/oops/objArrayKlass.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -39,6 +39,7 @@ assert(a->is_parsable(), "Can't publish unless parsable"); return a; } else { + report_java_out_of_memory("Requested array size exceeds VM limit"); THROW_OOP_0(Universe::out_of_memory_error_array_size()); } } else { diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/oops/objArrayOop.hpp --- a/hotspot/src/share/vm/oops/objArrayOop.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/oops/objArrayOop.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -38,6 +38,11 @@ } public: + // Returns the offset of the first element. + static int base_offset_in_bytes() { + return arrayOopDesc::base_offset_in_bytes(T_OBJECT); + } + // base is the address following the header. HeapWord* base() const { return (HeapWord*) arrayOopDesc::base(T_OBJECT); } diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/oops/typeArrayKlass.cpp --- a/hotspot/src/share/vm/oops/typeArrayKlass.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/oops/typeArrayKlass.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -80,6 +80,7 @@ assert(t->is_parsable(), "Don't publish unless parsable"); return t; } else { + report_java_out_of_memory("Requested array size exceeds VM limit"); THROW_OOP_0(Universe::out_of_memory_error_array_size()); } } else { diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/opto/block.cpp --- a/hotspot/src/share/vm/opto/block.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/opto/block.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -910,7 +910,16 @@ !(b->head()->is_Loop() && n->is_Phi()) && // See (+++) comment in reg_split.cpp !(n->jvms() != NULL && n->jvms()->is_monitor_use(k)) ) { - assert( b->find_node(def) < j, "uses must follow definitions" ); + bool is_loop = false; + if (n->is_Phi()) { + for( uint l = 1; l < def->req(); l++ ) { + if (n == def->in(l)) { + is_loop = true; + break; // Some kind of loop + } + } + } + assert( is_loop || b->find_node(def) < j, "uses must follow definitions" ); } if( def->is_SafePointScalarObject() ) { assert(_bbs[def->_idx] == b, "SafePointScalarObject Node should be at the same block as its SafePoint node"); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/opto/bytecodeInfo.cpp --- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -37,6 +37,7 @@ // Keep a private copy of the caller_jvms: _caller_jvms = new (C) JVMState(caller_jvms->method(), caller_tree->caller_jvms()); _caller_jvms->set_bci(caller_jvms->bci()); + assert(!caller_jvms->should_reexecute(), "there should be no reexecute bytecode with inlining"); } assert(_caller_jvms->same_calls_as(caller_jvms), "consistent JVMS"); assert((caller_tree == NULL ? 0 : caller_tree->inline_depth() + 1) == inline_depth(), "correct (redundant) depth parameter"); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/opto/callnode.cpp --- a/hotspot/src/share/vm/opto/callnode.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/opto/callnode.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -223,6 +223,7 @@ JVMState::JVMState(ciMethod* method, JVMState* caller) { assert(method != NULL, "must be valid call site"); _method = method; + _reexecute = Reexecute_Undefined; debug_only(_bci = -99); // random garbage value debug_only(_map = (SafePointNode*)-1); _caller = caller; @@ -237,6 +238,7 @@ JVMState::JVMState(int stack_size) { _method = NULL; _bci = InvocationEntryBci; + _reexecute = Reexecute_Undefined; debug_only(_map = (SafePointNode*)-1); _caller = NULL; _depth = 1; @@ -269,6 +271,7 @@ if (p->_method != q->_method) return false; if (p->_method == NULL) return true; // bci is irrelevant if (p->_bci != q->_bci) return false; + if (p->_reexecute != q->_reexecute) return false; p = p->caller(); q = q->caller(); if (p == q) return true; @@ -490,6 +493,7 @@ if (!printed) _method->print_short_name(st); st->print(" @ bci:%d",_bci); + st->print(" reexecute:%s", _reexecute==Reexecute_True?"true":"false"); } else { st->print(" runtime stub"); } @@ -509,8 +513,8 @@ } _map->dump(2); } - st->print("JVMS depth=%d loc=%d stk=%d mon=%d scalar=%d end=%d mondepth=%d sp=%d bci=%d method=", - depth(), locoff(), stkoff(), monoff(), scloff(), endoff(), monitor_depth(), sp(), bci()); + st->print("JVMS depth=%d loc=%d stk=%d mon=%d scalar=%d end=%d mondepth=%d sp=%d bci=%d reexecute=%s method=", + depth(), locoff(), stkoff(), monoff(), scloff(), endoff(), monitor_depth(), sp(), bci(), should_reexecute()?"true":"false"); if (_method == NULL) { st->print_cr("(none)"); } else { @@ -537,6 +541,7 @@ JVMState* JVMState::clone_shallow(Compile* C) const { JVMState* n = has_method() ? new (C) JVMState(_method, _caller) : new (C) JVMState(0); n->set_bci(_bci); + n->_reexecute = _reexecute; n->set_locoff(_locoff); n->set_stkoff(_stkoff); n->set_monoff(_monoff); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/opto/callnode.hpp --- a/hotspot/src/share/vm/opto/callnode.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/opto/callnode.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -178,6 +178,13 @@ // This provides a way to map the optimized program back into the interpreter, // or to let the GC mark the stack. class JVMState : public ResourceObj { +public: + typedef enum { + Reexecute_Undefined = -1, // not defined -- will be translated into false later + Reexecute_False = 0, // false -- do not reexecute + Reexecute_True = 1 // true -- reexecute the bytecode + } ReexecuteState; //Reexecute State + private: JVMState* _caller; // List pointer for forming scope chains uint _depth; // One mroe than caller depth, or one. @@ -188,10 +195,12 @@ uint _endoff; // Offset to end of input edge mapping uint _sp; // Jave Expression Stack Pointer for this state int _bci; // Byte Code Index of this JVM point + ReexecuteState _reexecute; // Whether this bytecode need to be re-executed ciMethod* _method; // Method Pointer SafePointNode* _map; // Map node associated with this scope public: friend class Compile; + friend class PreserveReexecuteState; // Because JVMState objects live over the entire lifetime of the // Compile object, they are allocated into the comp_arena, which @@ -222,16 +231,18 @@ bool is_mon(uint i) const { return i >= _monoff && i < _scloff; } bool is_scl(uint i) const { return i >= _scloff && i < _endoff; } - uint sp() const { return _sp; } - int bci() const { return _bci; } - bool has_method() const { return _method != NULL; } - ciMethod* method() const { assert(has_method(), ""); return _method; } - JVMState* caller() const { return _caller; } - SafePointNode* map() const { return _map; } - uint depth() const { return _depth; } - uint debug_start() const; // returns locoff of root caller - uint debug_end() const; // returns endoff of self - uint debug_size() const { + uint sp() const { return _sp; } + int bci() const { return _bci; } + bool should_reexecute() const { return _reexecute==Reexecute_True; } + bool is_reexecute_undefined() const { return _reexecute==Reexecute_Undefined; } + bool has_method() const { return _method != NULL; } + ciMethod* method() const { assert(has_method(), ""); return _method; } + JVMState* caller() const { return _caller; } + SafePointNode* map() const { return _map; } + uint depth() const { return _depth; } + uint debug_start() const; // returns locoff of root caller + uint debug_end() const; // returns endoff of self + uint debug_size() const { return loc_size() + sp() + mon_size() + scl_size(); } uint debug_depth() const; // returns sum of debug_size values at all depths @@ -267,7 +278,9 @@ } void set_map(SafePointNode *map) { _map = map; } void set_sp(uint sp) { _sp = sp; } - void set_bci(int bci) { _bci = bci; } + // _reexecute is initialized to "undefined" for a new bci + void set_bci(int bci) {if(_bci != bci)_reexecute=Reexecute_Undefined; _bci = bci; } + void set_should_reexecute(bool reexec) {_reexecute = reexec ? Reexecute_True : Reexecute_False;} // Miscellaneous utility functions JVMState* clone_deep(Compile* C) const; // recursively clones caller chain diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/opto/cfgnode.cpp --- a/hotspot/src/share/vm/opto/cfgnode.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/opto/cfgnode.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -1792,15 +1792,12 @@ if (UseCompressedOops && can_reshape && progress == NULL) { bool may_push = true; bool has_decodeN = false; - Node* in_decodeN = NULL; for (uint i=1; iis_DecodeN() && ii->bottom_type() == bottom_type()) { - // Note: in_decodeN is used only to define the type of new phi. - // Find a non dead path otherwise phi type will be wrong. + // Do optimization if a non dead path exist. if (ii->in(1)->bottom_type() != Type::TOP) { has_decodeN = true; - in_decodeN = ii->in(1); } } else if (!ii->is_Phi()) { may_push = false; @@ -1809,7 +1806,9 @@ if (has_decodeN && may_push) { PhaseIterGVN *igvn = phase->is_IterGVN(); - PhiNode *new_phi = PhiNode::make_blank(in(0), in_decodeN); + // Make narrow type for new phi. + const Type* narrow_t = TypeNarrowOop::make(this->bottom_type()->is_ptr()); + PhiNode* new_phi = new (phase->C, r->req()) PhiNode(r, narrow_t); uint orig_cnt = req(); for (uint i=1; ias_Phi() == this) { new_ii = new_phi; } else { - new_ii = new (phase->C, 2) EncodePNode(ii, in_decodeN->bottom_type()); + new_ii = new (phase->C, 2) EncodePNode(ii, narrow_t); igvn->register_new_node_with_optimizer(new_ii); } } diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/opto/graphKit.cpp --- a/hotspot/src/share/vm/opto/graphKit.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/opto/graphKit.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -620,6 +620,16 @@ assert(kit->stopped(), "cutout code must stop, throw, return, etc."); } +//---------------------------PreserveReexecuteState---------------------------- +PreserveReexecuteState::PreserveReexecuteState(GraphKit* kit) { + _kit = kit; + _sp = kit->sp(); + _reexecute = kit->jvms()->_reexecute; +} +PreserveReexecuteState::~PreserveReexecuteState() { + _kit->jvms()->_reexecute = _reexecute; + _kit->set_sp(_sp); +} //------------------------------clone_map-------------------------------------- // Implementation of PreserveJVMState @@ -738,6 +748,18 @@ #endif //ASSERT +// Helper function for enforcing certain bytecodes to reexecute if +// deoptimization happens +static bool should_reexecute_implied_by_bytecode(JVMState *jvms) { + ciMethod* cur_method = jvms->method(); + int cur_bci = jvms->bci(); + if (cur_method != NULL && cur_bci != InvocationEntryBci) { + Bytecodes::Code code = cur_method->java_code_at_bci(cur_bci); + return Interpreter::bytecode_should_reexecute(code); + } else + return false; +} + // Helper function for adding JVMState and debug information to node void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw) { // Add the safepoint edges to the call (or other safepoint). @@ -781,6 +803,13 @@ JVMState* out_jvms = youngest_jvms->clone_deep(C); call->set_jvms(out_jvms); // Start jvms list for call node + // For a known set of bytecodes, the interpreter should reexecute them if + // deoptimization happens. We set the reexecute state for them here + if (out_jvms->is_reexecute_undefined() && //don't change if already specified + should_reexecute_implied_by_bytecode(out_jvms)) { + out_jvms->set_should_reexecute(true); //NOTE: youngest_jvms not changed + } + // Presize the call: debug_only(uint non_debug_edges = call->req()); call->add_req_batch(top(), youngest_jvms->debug_depth()); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/opto/graphKit.hpp --- a/hotspot/src/share/vm/opto/graphKit.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/opto/graphKit.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -763,3 +763,16 @@ BuildCutout(GraphKit* kit, Node* p, float prob, float cnt = COUNT_UNKNOWN); ~BuildCutout(); }; + +// Helper class to preserve the original _reexecute bit and _sp and restore +// them back +class PreserveReexecuteState: public StackObj { + protected: + GraphKit* _kit; + uint _sp; + JVMState::ReexecuteState _reexecute; + + public: + PreserveReexecuteState(GraphKit* kit); + ~PreserveReexecuteState(); +}; diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/opto/library_call.cpp --- a/hotspot/src/share/vm/opto/library_call.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/opto/library_call.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -2064,7 +2064,7 @@ // See if it is a narrow oop array. if (adr_type->isa_aryptr()) { - if (adr_type->offset() >= objArrayOopDesc::base_offset_in_bytes(type)) { + if (adr_type->offset() >= objArrayOopDesc::base_offset_in_bytes()) { const TypeOopPtr *elem_type = adr_type->is_aryptr()->elem()->isa_oopptr(); if (elem_type != NULL) { sharpened_klass = elem_type->klass(); @@ -3169,78 +3169,85 @@ Node* end = is_copyOfRange? argument(2): argument(1); Node* array_type_mirror = is_copyOfRange? argument(3): argument(2); - _sp += nargs; // set original stack for use by uncommon_trap - array_type_mirror = do_null_check(array_type_mirror, T_OBJECT); - original = do_null_check(original, T_OBJECT); - _sp -= nargs; - - // Check if a null path was taken unconditionally. - if (stopped()) return true; - - Node* orig_length = load_array_length(original); - - Node* klass_node = load_klass_from_mirror(array_type_mirror, false, nargs, - NULL, 0); - _sp += nargs; // set original stack for use by uncommon_trap - klass_node = do_null_check(klass_node, T_OBJECT); - _sp -= nargs; - - RegionNode* bailout = new (C, 1) RegionNode(1); - record_for_igvn(bailout); - - // Despite the generic type of Arrays.copyOf, the mirror might be int, int[], etc. - // Bail out if that is so. - Node* not_objArray = generate_non_objArray_guard(klass_node, bailout); - if (not_objArray != NULL) { - // Improve the klass node's type from the new optimistic assumption: - ciKlass* ak = ciArrayKlass::make(env()->Object_klass()); - const Type* akls = TypeKlassPtr::make(TypePtr::NotNull, ak, 0/*offset*/); - Node* cast = new (C, 2) CastPPNode(klass_node, akls); - cast->init_req(0, control()); - klass_node = _gvn.transform(cast); - } - - // Bail out if either start or end is negative. - generate_negative_guard(start, bailout, &start); - generate_negative_guard(end, bailout, &end); - - Node* length = end; - if (_gvn.type(start) != TypeInt::ZERO) { - length = _gvn.transform( new (C, 3) SubINode(end, start) ); - } - - // Bail out if length is negative. - // ...Not needed, since the new_array will throw the right exception. - //generate_negative_guard(length, bailout, &length); - - if (bailout->req() > 1) { - PreserveJVMState pjvms(this); - set_control( _gvn.transform(bailout) ); - _sp += nargs; // push the arguments back on the stack - uncommon_trap(Deoptimization::Reason_intrinsic, - Deoptimization::Action_maybe_recompile); - } - - if (!stopped()) { - // How many elements will we copy from the original? - // The answer is MinI(orig_length - start, length). - Node* orig_tail = _gvn.transform( new(C, 3) SubINode(orig_length, start) ); - Node* moved = generate_min_max(vmIntrinsics::_min, orig_tail, length); - - const bool raw_mem_only = true; - Node* newcopy = new_array(klass_node, length, nargs, raw_mem_only); - - // Generate a direct call to the right arraycopy function(s). - // We know the copy is disjoint but we might not know if the - // oop stores need checking. - // Extreme case: Arrays.copyOf((Integer[])x, 10, String[].class). - // This will fail a store-check if x contains any non-nulls. - bool disjoint_bases = true; - bool length_never_negative = true; - generate_arraycopy(TypeAryPtr::OOPS, T_OBJECT, - original, start, newcopy, intcon(0), moved, - disjoint_bases, length_never_negative); - + Node* newcopy; + + //set the original stack and the reexecute bit for the interpreter to reexecute + //the bytecode that invokes Arrays.copyOf if deoptimization happens + { PreserveReexecuteState preexecs(this); + _sp += nargs; + jvms()->set_should_reexecute(true); + + array_type_mirror = do_null_check(array_type_mirror, T_OBJECT); + original = do_null_check(original, T_OBJECT); + + // Check if a null path was taken unconditionally. + if (stopped()) return true; + + Node* orig_length = load_array_length(original); + + Node* klass_node = load_klass_from_mirror(array_type_mirror, false, 0, + NULL, 0); + klass_node = do_null_check(klass_node, T_OBJECT); + + RegionNode* bailout = new (C, 1) RegionNode(1); + record_for_igvn(bailout); + + // Despite the generic type of Arrays.copyOf, the mirror might be int, int[], etc. + // Bail out if that is so. + Node* not_objArray = generate_non_objArray_guard(klass_node, bailout); + if (not_objArray != NULL) { + // Improve the klass node's type from the new optimistic assumption: + ciKlass* ak = ciArrayKlass::make(env()->Object_klass()); + const Type* akls = TypeKlassPtr::make(TypePtr::NotNull, ak, 0/*offset*/); + Node* cast = new (C, 2) CastPPNode(klass_node, akls); + cast->init_req(0, control()); + klass_node = _gvn.transform(cast); + } + + // Bail out if either start or end is negative. + generate_negative_guard(start, bailout, &start); + generate_negative_guard(end, bailout, &end); + + Node* length = end; + if (_gvn.type(start) != TypeInt::ZERO) { + length = _gvn.transform( new (C, 3) SubINode(end, start) ); + } + + // Bail out if length is negative. + // ...Not needed, since the new_array will throw the right exception. + //generate_negative_guard(length, bailout, &length); + + if (bailout->req() > 1) { + PreserveJVMState pjvms(this); + set_control( _gvn.transform(bailout) ); + uncommon_trap(Deoptimization::Reason_intrinsic, + Deoptimization::Action_maybe_recompile); + } + + if (!stopped()) { + + // How many elements will we copy from the original? + // The answer is MinI(orig_length - start, length). + Node* orig_tail = _gvn.transform( new(C, 3) SubINode(orig_length, start) ); + Node* moved = generate_min_max(vmIntrinsics::_min, orig_tail, length); + + const bool raw_mem_only = true; + newcopy = new_array(klass_node, length, 0, raw_mem_only); + + // Generate a direct call to the right arraycopy function(s). + // We know the copy is disjoint but we might not know if the + // oop stores need checking. + // Extreme case: Arrays.copyOf((Integer[])x, 10, String[].class). + // This will fail a store-check if x contains any non-nulls. + bool disjoint_bases = true; + bool length_never_negative = true; + generate_arraycopy(TypeAryPtr::OOPS, T_OBJECT, + original, start, newcopy, intcon(0), moved, + disjoint_bases, length_never_negative); + } + } //original reexecute and sp are set back here + + if(!stopped()) { push(newcopy); } @@ -3992,146 +3999,159 @@ // bool LibraryCallKit::inline_native_clone(bool is_virtual) { int nargs = 1; - Node* obj = null_check_receiver(callee()); - if (stopped()) return true; - Node* obj_klass = load_object_klass(obj); - const TypeKlassPtr* tklass = _gvn.type(obj_klass)->isa_klassptr(); - const TypeOopPtr* toop = ((tklass != NULL) + PhiNode* result_val; + + //set the original stack and the reexecute bit for the interpreter to reexecute + //the bytecode that invokes Object.clone if deoptimization happens + { PreserveReexecuteState preexecs(this); + jvms()->set_should_reexecute(true); + + //null_check_receiver will adjust _sp (push and pop) + Node* obj = null_check_receiver(callee()); + if (stopped()) return true; + + _sp += nargs; + + Node* obj_klass = load_object_klass(obj); + const TypeKlassPtr* tklass = _gvn.type(obj_klass)->isa_klassptr(); + const TypeOopPtr* toop = ((tklass != NULL) ? tklass->as_instance_type() : TypeInstPtr::NOTNULL); - // Conservatively insert a memory barrier on all memory slices. - // Do not let writes into the original float below the clone. - insert_mem_bar(Op_MemBarCPUOrder); - - // paths into result_reg: - enum { - _slow_path = 1, // out-of-line call to clone method (virtual or not) - _objArray_path, // plain array allocation, plus arrayof_oop_arraycopy - _array_path, // plain array allocation, plus arrayof_long_arraycopy - _instance_path, // plain instance allocation, plus arrayof_long_arraycopy - PATH_LIMIT - }; - RegionNode* result_reg = new(C, PATH_LIMIT) RegionNode(PATH_LIMIT); - PhiNode* result_val = new(C, PATH_LIMIT) PhiNode(result_reg, - TypeInstPtr::NOTNULL); - PhiNode* result_i_o = new(C, PATH_LIMIT) PhiNode(result_reg, Type::ABIO); - PhiNode* result_mem = new(C, PATH_LIMIT) PhiNode(result_reg, Type::MEMORY, - TypePtr::BOTTOM); - record_for_igvn(result_reg); - - const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM; - int raw_adr_idx = Compile::AliasIdxRaw; - const bool raw_mem_only = true; - - Node* array_ctl = generate_array_guard(obj_klass, (RegionNode*)NULL); - if (array_ctl != NULL) { - // It's an array. - PreserveJVMState pjvms(this); - set_control(array_ctl); - Node* obj_length = load_array_length(obj); - Node* obj_size = NULL; - Node* alloc_obj = new_array(obj_klass, obj_length, nargs, - raw_mem_only, &obj_size); - - if (!use_ReduceInitialCardMarks()) { - // If it is an oop array, it requires very special treatment, - // because card marking is required on each card of the array. - Node* is_obja = generate_objArray_guard(obj_klass, (RegionNode*)NULL); - if (is_obja != NULL) { - PreserveJVMState pjvms2(this); - set_control(is_obja); - // Generate a direct call to the right arraycopy function(s). - bool disjoint_bases = true; - bool length_never_negative = true; - generate_arraycopy(TypeAryPtr::OOPS, T_OBJECT, - obj, intcon(0), alloc_obj, intcon(0), - obj_length, - disjoint_bases, length_never_negative); - result_reg->init_req(_objArray_path, control()); - result_val->init_req(_objArray_path, alloc_obj); - result_i_o ->set_req(_objArray_path, i_o()); - result_mem ->set_req(_objArray_path, reset_memory()); + // Conservatively insert a memory barrier on all memory slices. + // Do not let writes into the original float below the clone. + insert_mem_bar(Op_MemBarCPUOrder); + + // paths into result_reg: + enum { + _slow_path = 1, // out-of-line call to clone method (virtual or not) + _objArray_path, // plain array allocation, plus arrayof_oop_arraycopy + _array_path, // plain array allocation, plus arrayof_long_arraycopy + _instance_path, // plain instance allocation, plus arrayof_long_arraycopy + PATH_LIMIT + }; + RegionNode* result_reg = new(C, PATH_LIMIT) RegionNode(PATH_LIMIT); + result_val = new(C, PATH_LIMIT) PhiNode(result_reg, + TypeInstPtr::NOTNULL); + PhiNode* result_i_o = new(C, PATH_LIMIT) PhiNode(result_reg, Type::ABIO); + PhiNode* result_mem = new(C, PATH_LIMIT) PhiNode(result_reg, Type::MEMORY, + TypePtr::BOTTOM); + record_for_igvn(result_reg); + + const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM; + int raw_adr_idx = Compile::AliasIdxRaw; + const bool raw_mem_only = true; + + + Node* array_ctl = generate_array_guard(obj_klass, (RegionNode*)NULL); + if (array_ctl != NULL) { + // It's an array. + PreserveJVMState pjvms(this); + set_control(array_ctl); + Node* obj_length = load_array_length(obj); + Node* obj_size = NULL; + Node* alloc_obj = new_array(obj_klass, obj_length, 0, + raw_mem_only, &obj_size); + + if (!use_ReduceInitialCardMarks()) { + // If it is an oop array, it requires very special treatment, + // because card marking is required on each card of the array. + Node* is_obja = generate_objArray_guard(obj_klass, (RegionNode*)NULL); + if (is_obja != NULL) { + PreserveJVMState pjvms2(this); + set_control(is_obja); + // Generate a direct call to the right arraycopy function(s). + bool disjoint_bases = true; + bool length_never_negative = true; + generate_arraycopy(TypeAryPtr::OOPS, T_OBJECT, + obj, intcon(0), alloc_obj, intcon(0), + obj_length, + disjoint_bases, length_never_negative); + result_reg->init_req(_objArray_path, control()); + result_val->init_req(_objArray_path, alloc_obj); + result_i_o ->set_req(_objArray_path, i_o()); + result_mem ->set_req(_objArray_path, reset_memory()); + } + } + // We can dispense with card marks if we know the allocation + // comes out of eden (TLAB)... In fact, ReduceInitialCardMarks + // causes the non-eden paths to simulate a fresh allocation, + // insofar that no further card marks are required to initialize + // the object. + + // Otherwise, there are no card marks to worry about. + + if (!stopped()) { + copy_to_clone(obj, alloc_obj, obj_size, true, false); + + // Present the results of the copy. + result_reg->init_req(_array_path, control()); + result_val->init_req(_array_path, alloc_obj); + result_i_o ->set_req(_array_path, i_o()); + result_mem ->set_req(_array_path, reset_memory()); } } - // We can dispense with card marks if we know the allocation - // comes out of eden (TLAB)... In fact, ReduceInitialCardMarks - // causes the non-eden paths to simulate a fresh allocation, - // insofar that no further card marks are required to initialize - // the object. - - // Otherwise, there are no card marks to worry about. + + // We only go to the instance fast case code if we pass a number of guards. + // The paths which do not pass are accumulated in the slow_region. + RegionNode* slow_region = new (C, 1) RegionNode(1); + record_for_igvn(slow_region); + if (!stopped()) { + // It's an instance (we did array above). Make the slow-path tests. + // If this is a virtual call, we generate a funny guard. We grab + // the vtable entry corresponding to clone() from the target object. + // If the target method which we are calling happens to be the + // Object clone() method, we pass the guard. We do not need this + // guard for non-virtual calls; the caller is known to be the native + // Object clone(). + if (is_virtual) { + generate_virtual_guard(obj_klass, slow_region); + } + + // The object must be cloneable and must not have a finalizer. + // Both of these conditions may be checked in a single test. + // We could optimize the cloneable test further, but we don't care. + generate_access_flags_guard(obj_klass, + // Test both conditions: + JVM_ACC_IS_CLONEABLE | JVM_ACC_HAS_FINALIZER, + // Must be cloneable but not finalizer: + JVM_ACC_IS_CLONEABLE, + slow_region); + } if (!stopped()) { - copy_to_clone(obj, alloc_obj, obj_size, true, false); - - // Present the results of the copy. - result_reg->init_req(_array_path, control()); - result_val->init_req(_array_path, alloc_obj); - result_i_o ->set_req(_array_path, i_o()); - result_mem ->set_req(_array_path, reset_memory()); - } - } - - // We only go to the instance fast case code if we pass a number of guards. - // The paths which do not pass are accumulated in the slow_region. - RegionNode* slow_region = new (C, 1) RegionNode(1); - record_for_igvn(slow_region); - if (!stopped()) { - // It's an instance (we did array above). Make the slow-path tests. - // If this is a virtual call, we generate a funny guard. We grab - // the vtable entry corresponding to clone() from the target object. - // If the target method which we are calling happens to be the - // Object clone() method, we pass the guard. We do not need this - // guard for non-virtual calls; the caller is known to be the native - // Object clone(). - if (is_virtual) { - generate_virtual_guard(obj_klass, slow_region); + // It's an instance, and it passed the slow-path tests. + PreserveJVMState pjvms(this); + Node* obj_size = NULL; + Node* alloc_obj = new_instance(obj_klass, NULL, raw_mem_only, &obj_size); + + copy_to_clone(obj, alloc_obj, obj_size, false, !use_ReduceInitialCardMarks()); + + // Present the results of the slow call. + result_reg->init_req(_instance_path, control()); + result_val->init_req(_instance_path, alloc_obj); + result_i_o ->set_req(_instance_path, i_o()); + result_mem ->set_req(_instance_path, reset_memory()); } - // The object must be cloneable and must not have a finalizer. - // Both of these conditions may be checked in a single test. - // We could optimize the cloneable test further, but we don't care. - generate_access_flags_guard(obj_klass, - // Test both conditions: - JVM_ACC_IS_CLONEABLE | JVM_ACC_HAS_FINALIZER, - // Must be cloneable but not finalizer: - JVM_ACC_IS_CLONEABLE, - slow_region); - } - - if (!stopped()) { - // It's an instance, and it passed the slow-path tests. - PreserveJVMState pjvms(this); - Node* obj_size = NULL; - Node* alloc_obj = new_instance(obj_klass, NULL, raw_mem_only, &obj_size); - - copy_to_clone(obj, alloc_obj, obj_size, false, !use_ReduceInitialCardMarks()); - - // Present the results of the slow call. - result_reg->init_req(_instance_path, control()); - result_val->init_req(_instance_path, alloc_obj); - result_i_o ->set_req(_instance_path, i_o()); - result_mem ->set_req(_instance_path, reset_memory()); - } - - // Generate code for the slow case. We make a call to clone(). - set_control(_gvn.transform(slow_region)); - if (!stopped()) { - PreserveJVMState pjvms(this); - CallJavaNode* slow_call = generate_method_call(vmIntrinsics::_clone, is_virtual); - Node* slow_result = set_results_for_java_call(slow_call); - // this->control() comes from set_results_for_java_call - result_reg->init_req(_slow_path, control()); - result_val->init_req(_slow_path, slow_result); - result_i_o ->set_req(_slow_path, i_o()); - result_mem ->set_req(_slow_path, reset_memory()); - } - - // Return the combined state. - set_control( _gvn.transform(result_reg) ); - set_i_o( _gvn.transform(result_i_o) ); - set_all_memory( _gvn.transform(result_mem) ); + // Generate code for the slow case. We make a call to clone(). + set_control(_gvn.transform(slow_region)); + if (!stopped()) { + PreserveJVMState pjvms(this); + CallJavaNode* slow_call = generate_method_call(vmIntrinsics::_clone, is_virtual); + Node* slow_result = set_results_for_java_call(slow_call); + // this->control() comes from set_results_for_java_call + result_reg->init_req(_slow_path, control()); + result_val->init_req(_slow_path, slow_result); + result_i_o ->set_req(_slow_path, i_o()); + result_mem ->set_req(_slow_path, reset_memory()); + } + + // Return the combined state. + set_control( _gvn.transform(result_reg) ); + set_i_o( _gvn.transform(result_i_o) ); + set_all_memory( _gvn.transform(result_mem) ); + } //original reexecute and sp are set back here push(_gvn.transform(result_val)); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/opto/mulnode.cpp --- a/hotspot/src/share/vm/opto/mulnode.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/opto/mulnode.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -608,16 +608,14 @@ } // Are we masking a long that was converted from an int with a mask - // that fits in 32-bits? Commute them and use an AndINode. - if (op == Op_ConvI2L && (mask & CONST64(0xFFFFFFFF00000000)) == 0) { - // If we are doing an UI2L conversion (i.e. the mask is - // 0x00000000FFFFFFFF) we cannot convert the AndL to an AndI - // because the AndI would be optimized away later in Identity. - if (mask != CONST64(0x00000000FFFFFFFF)) { - Node* andi = new (phase->C, 3) AndINode(in1->in(1), phase->intcon(mask)); - andi = phase->transform(andi); - return new (phase->C, 2) ConvI2LNode(andi); - } + // that fits in 32-bits? Commute them and use an AndINode. Don't + // convert masks which would cause a sign extension of the integer + // value. This check includes UI2L masks (0x00000000FFFFFFFF) which + // would be optimized away later in Identity. + if (op == Op_ConvI2L && (mask & CONST64(0xFFFFFFFF80000000)) == 0) { + Node* andi = new (phase->C, 3) AndINode(in1->in(1), phase->intcon(mask)); + andi = phase->transform(andi); + return new (phase->C, 2) ConvI2LNode(andi); } // Masking off sign bits? Dont make them! diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/opto/output.cpp --- a/hotspot/src/share/vm/opto/output.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/opto/output.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -911,8 +911,9 @@ ciMethod* scope_method = method ? method : _method; // Describe the scope here assert(jvms->bci() >= InvocationEntryBci && jvms->bci() <= 0x10000, "must be a valid or entry BCI"); + assert(!jvms->should_reexecute() || depth==max_depth, "reexecute allowed only for the youngest"); // Now we can describe the scope. - debug_info()->describe_scope(safepoint_pc_offset,scope_method,jvms->bci(),locvals,expvals,monvals); + debug_info()->describe_scope(safepoint_pc_offset,scope_method,jvms->bci(),jvms->should_reexecute(),locvals,expvals,monvals); } // End jvms loop // Mark the end of the scope set. @@ -994,7 +995,8 @@ for (int depth = 1; depth <= max_depth; depth++) { JVMState* jvms = youngest_jvms->of_depth(depth); ciMethod* method = jvms->has_method() ? jvms->method() : NULL; - debug_info->describe_scope(pc_offset, method, jvms->bci()); + assert(!jvms->should_reexecute() || depth==max_depth, "reexecute allowed only for the youngest"); + debug_info->describe_scope(pc_offset, method, jvms->bci(), jvms->should_reexecute()); } // Mark the end of the scope set. diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/prims/jvm.cpp --- a/hotspot/src/share/vm/prims/jvm.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/prims/jvm.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -638,11 +638,54 @@ if (PrintJVMWarnings) warning("JVM_ResolveClass not implemented"); JVM_END -// Common implementation for JVM_FindClassFromBootLoader and -// JVM_FindClassFromLoader -static jclass jvm_find_class_from_class_loader(JNIEnv* env, const char* name, - jboolean init, jobject loader, - jboolean throwError, TRAPS) { + +// Returns a class loaded by the bootstrap class loader; or null +// if not found. ClassNotFoundException is not thrown. +// +// Rationale behind JVM_FindClassFromBootLoader +// a> JVM_FindClassFromClassLoader was never exported in the export tables. +// b> because of (a) java.dll has a direct dependecy on the unexported +// private symbol "_JVM_FindClassFromClassLoader@20". +// c> the launcher cannot use the private symbol as it dynamically opens +// the entry point, so if something changes, the launcher will fail +// unexpectedly at runtime, it is safest for the launcher to dlopen a +// stable exported interface. +// d> re-exporting JVM_FindClassFromClassLoader as public, will cause its +// signature to change from _JVM_FindClassFromClassLoader@20 to +// JVM_FindClassFromClassLoader and will not be backward compatible +// with older JDKs. +// Thus a public/stable exported entry point is the right solution, +// public here means public in linker semantics, and is exported only +// to the JDK, and is not intended to be a public API. + +JVM_ENTRY(jclass, JVM_FindClassFromBootLoader(JNIEnv* env, + const char* name)) + JVMWrapper2("JVM_FindClassFromBootLoader %s", name); + + // Java libraries should ensure that name is never null... + if (name == NULL || (int)strlen(name) > symbolOopDesc::max_length()) { + // It's impossible to create this class; the name cannot fit + // into the constant pool. + return NULL; + } + + symbolHandle h_name = oopFactory::new_symbol_handle(name, CHECK_NULL); + klassOop k = SystemDictionary::resolve_or_null(h_name, CHECK_NULL); + if (k == NULL) { + return NULL; + } + + if (TraceClassResolution) { + trace_class_resolution(k); + } + return (jclass) JNIHandles::make_local(env, Klass::cast(k)->java_mirror()); +JVM_END + +JVM_ENTRY(jclass, JVM_FindClassFromClassLoader(JNIEnv* env, const char* name, + jboolean init, jobject loader, + jboolean throwError)) + JVMWrapper3("JVM_FindClassFromClassLoader %s throw %s", name, + throwError ? "error" : "exception"); // Java libraries should ensure that name is never null... if (name == NULL || (int)strlen(name) > symbolOopDesc::max_length()) { // It's impossible to create this class; the name cannot fit @@ -662,40 +705,6 @@ trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result))); } return result; -} - -// Rationale behind JVM_FindClassFromBootLoader -// a> JVM_FindClassFromClassLoader was never exported in the export tables. -// b> because of (a) java.dll has a direct dependecy on the unexported -// private symbol "_JVM_FindClassFromClassLoader@20". -// c> the launcher cannot use the private symbol as it dynamically opens -// the entry point, so if something changes, the launcher will fail -// unexpectedly at runtime, it is safest for the launcher to dlopen a -// stable exported interface. -// d> re-exporting JVM_FindClassFromClassLoader as public, will cause its -// signature to change from _JVM_FindClassFromClassLoader@20 to -// JVM_FindClassFromClassLoader and will not be backward compatible -// with older JDKs. -// Thus a public/stable exported entry point is the right solution, -// public here means public in linker semantics, and is exported only -// to the JDK, and is not intended to be a public API. - -JVM_ENTRY(jclass, JVM_FindClassFromBootLoader(JNIEnv* env, - const char* name, - jboolean throwError)) - JVMWrapper3("JVM_FindClassFromBootLoader %s throw %s", name, - throwError ? "error" : "exception"); - return jvm_find_class_from_class_loader(env, name, JNI_FALSE, - (jobject)NULL, throwError, THREAD); -JVM_END - -JVM_ENTRY(jclass, JVM_FindClassFromClassLoader(JNIEnv* env, const char* name, - jboolean init, jobject loader, - jboolean throwError)) - JVMWrapper3("JVM_FindClassFromClassLoader %s throw %s", name, - throwError ? "error" : "exception"); - return jvm_find_class_from_class_loader(env, name, init, loader, - throwError, THREAD); JVM_END @@ -756,6 +765,20 @@ static jclass jvm_define_class_common(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd, const char *source, TRAPS) { if (source == NULL) source = "__JVM_DefineClass__"; + assert(THREAD->is_Java_thread(), "must be a JavaThread"); + JavaThread* jt = (JavaThread*) THREAD; + + PerfClassTraceTime vmtimer(ClassLoader::perf_define_appclass_time(), + ClassLoader::perf_define_appclass_selftime(), + ClassLoader::perf_define_appclasses(), + jt->get_thread_stat()->perf_recursion_counts_addr(), + jt->get_thread_stat()->perf_timers_addr(), + PerfClassTraceTime::DEFINE_CLASS); + + if (UsePerfData) { + ClassLoader::perf_app_classfile_bytes_read()->inc(len); + } + // Since exceptions can be thrown, class initialization can take place // if name is NULL no check for class name in .class stream has to be made. symbolHandle class_name; @@ -3905,6 +3928,7 @@ // The Java level wrapper will perform the necessary security check allowing // us to pass the NULL as the initiating class loader. klassOop klass = SystemDictionary::resolve_or_fail(name, loader, protection_domain, throwError != 0, CHECK_NULL); + KlassHandle klass_handle(THREAD, klass); // Check if we should initialize the class if (init && klass_handle->oop_is_instance()) { diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/prims/jvm.h --- a/hotspot/src/share/vm/prims/jvm.h Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/prims/jvm.h Wed Jul 05 16:59:43 2017 +0200 @@ -390,15 +390,10 @@ jobject loader, jboolean throwError); /* - * Find a class from a boot class loader. Throw ClassNotFoundException - * or NoClassDefFoundError depending on the value of the last - * argument. This is the same as FindClassFromClassLoader but provided - * as a convenience method exported correctly on all platforms for - * JSR 277 launcher class loading. + * Find a class from a boot class loader. Returns NULL if class not found. */ JNIEXPORT jclass JNICALL -JVM_FindClassFromBootLoader(JNIEnv *env, const char *name, - jboolean throwError); +JVM_FindClassFromBootLoader(JNIEnv *env, const char *name); /* * Find a class from a given class. diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/prims/jvmtiExport.cpp --- a/hotspot/src/share/vm/prims/jvmtiExport.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2427,6 +2427,11 @@ return; } + if (ForceFullGCJVMTIEpilogues) { + // force 'Full GC' was done semantics for JVMTI GC epilogues + _full = true; + } + // GarbageCollectionStart event posted from VM thread - okay because // JVMTI is clear that the "world is stopped" and callback shouldn't // try to call into the VM. diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/runtime/arguments.cpp --- a/hotspot/src/share/vm/runtime/arguments.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -1054,7 +1054,15 @@ // Unless explicitly requested otherwise, size young gen // for "short" pauses ~ 4M*ParallelGCThreads - if (FLAG_IS_DEFAULT(MaxNewSize)) { // MaxNewSize not set at command-line + + // If either MaxNewSize or NewRatio is set on the command line, + // assume the user is trying to set the size of the young gen. + + if (FLAG_IS_DEFAULT(MaxNewSize) && FLAG_IS_DEFAULT(NewRatio)) { + + // Set MaxNewSize to our calculated preferred_max_new_size unless + // NewSize was set on the command line and it is larger than + // preferred_max_new_size. if (!FLAG_IS_DEFAULT(NewSize)) { // NewSize explicitly set at command-line FLAG_SET_ERGO(uintx, MaxNewSize, MAX2(NewSize, preferred_max_new_size)); } else { @@ -1063,15 +1071,32 @@ if(PrintGCDetails && Verbose) { // Too early to use gclog_or_tty tty->print_cr("Ergo set MaxNewSize: " SIZE_FORMAT, MaxNewSize); - } - } - // Unless explicitly requested otherwise, prefer a large - // Old to Young gen size so as to shift the collection load - // to the old generation concurrent collector - if (FLAG_IS_DEFAULT(NewRatio)) { + } + + // Unless explicitly requested otherwise, prefer a large + // Old to Young gen size so as to shift the collection load + // to the old generation concurrent collector + + // If this is only guarded by FLAG_IS_DEFAULT(NewRatio) + // then NewSize and OldSize may be calculated. That would + // generally lead to some differences with ParNewGC for which + // there was no obvious reason. Also limit to the case where + // MaxNewSize has not been set. + FLAG_SET_ERGO(intx, NewRatio, MAX2(NewRatio, new_ratio)); - size_t min_new = align_size_up(ScaleForWordSize(min_new_default), os::vm_page_size()); + // Code along this path potentially sets NewSize and OldSize + + // Calculate the desired minimum size of the young gen but if + // NewSize has been set on the command line, use it here since + // it should be the final value. + size_t min_new; + if (FLAG_IS_DEFAULT(NewSize)) { + min_new = align_size_up(ScaleForWordSize(min_new_default), + os::vm_page_size()); + } else { + min_new = NewSize; + } size_t prev_initial_size = initial_heap_size(); if (prev_initial_size != 0 && prev_initial_size < min_new+OldSize) { set_initial_heap_size(min_new+OldSize); @@ -1083,9 +1108,11 @@ initial_heap_size()/M, prev_initial_size/M); } } + // MaxHeapSize is aligned down in collectorPolicy - size_t max_heap = align_size_down(MaxHeapSize, - CardTableRS::ct_max_alignment_constraint()); + size_t max_heap = + align_size_down(MaxHeapSize, + CardTableRS::ct_max_alignment_constraint()); if(PrintGCDetails && Verbose) { // Too early to use gclog_or_tty @@ -1150,8 +1177,9 @@ // CMSParPromoteBlocksToClaim is a collector-specific flag, so // we'll let it to take precedence. jio_fprintf(defaultStream::error_stream(), - "Both OldPLABSize and CMSParPromoteBlocksToClaim options are specified " - "for the CMS collector. CMSParPromoteBlocksToClaim will take precedence.\n"); + "Both OldPLABSize and CMSParPromoteBlocksToClaim" + " options are specified for the CMS collector." + " CMSParPromoteBlocksToClaim will take precedence.\n"); } } } diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/runtime/atomic.hpp --- a/hotspot/src/share/vm/runtime/atomic.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/runtime/atomic.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -39,6 +39,8 @@ static void store_ptr(intptr_t store_value, volatile intptr_t* dest); static void store_ptr(void* store_value, volatile void* dest); + static jlong load(volatile jlong* src); + // Atomically add to a location, return updated value static jint add (jint add_value, volatile jint* dest); static intptr_t add_ptr(intptr_t add_value, volatile intptr_t* dest); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -1082,6 +1082,9 @@ product(ccstr, TraceJVMTI, NULL, \ "Trace flags for JVMTI functions and events") \ \ + product(bool, ForceFullGCJVMTIEpilogues, false, \ + "Force 'Full GC' was done semantics for JVMTI GC epilogues") \ + \ /* This option can change an EMCP method into an obsolete method. */ \ /* This can affect tests that except specific methods to be EMCP. */ \ /* This option should be used with caution. */ \ @@ -2924,12 +2927,6 @@ "how many entries we'll try to leave on the stack during " \ "parallel GC") \ \ - product(intx, DCQBarrierQueueBufferSize, 256, \ - "Number of elements in a dirty card queue buffer") \ - \ - product(intx, DCQBarrierProcessCompletedThreshold, 5, \ - "Number of completed dirty card buffers to trigger processing.") \ - \ /* stack parameters */ \ product_pd(intx, StackYellowPages, \ "Number of yellow zone (recoverable overflows) pages") \ @@ -3037,6 +3034,9 @@ "Wait for this many CI accesses to occur in all compiles before " \ "beginning to throw OutOfMemoryErrors in each compile") \ \ + notproduct(bool, CIObjectFactoryVerify, false, \ + "enable potentially expensive verification in ciObjectFactory") \ + \ /* Priorities */ \ product_pd(bool, UseThreadPriorities, "Use native thread priorities") \ \ @@ -3287,7 +3287,7 @@ product(uintx, SharedReadWriteSize, 12*M, \ "Size of read-write space in permanent generation (in bytes)") \ \ - product(uintx, SharedReadOnlySize, 8*M, \ + product(uintx, SharedReadOnlySize, 10*M, \ "Size of read-only space in permanent generation (in bytes)") \ \ product(uintx, SharedMiscDataSize, 4*M, \ @@ -3312,7 +3312,7 @@ product(bool, AnonymousClasses, false, \ "support sun.misc.Unsafe.defineAnonymousClass") \ \ - product(bool, EnableMethodHandles, false, \ + experimental(bool, EnableMethodHandles, false, \ "support method handles (true by default under JSR 292)") \ \ diagnostic(intx, MethodHandlePushLimit, 3, \ @@ -3327,7 +3327,7 @@ diagnostic(bool, OptimizeMethodHandles, true, \ "when constructing method handles, try to improve them") \ \ - product(bool, EnableInvokeDynamic, false, \ + experimental(bool, EnableInvokeDynamic, false, \ "recognize the invokedynamic instruction") \ \ develop(bool, TraceInvokeDynamic, false, \ diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/runtime/perfData.hpp --- a/hotspot/src/share/vm/runtime/perfData.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/runtime/perfData.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -868,6 +868,10 @@ {counter = PerfDataManager::create_counter(counter_ns, counter_name, \ PerfData::U_Events,CHECK);} +#define NEWPERFBYTECOUNTER(counter, counter_ns, counter_name) \ + {counter = PerfDataManager::create_counter(counter_ns, counter_name, \ + PerfData::U_Bytes,CHECK);} + // Utility Classes /* diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/runtime/vframe.hpp --- a/hotspot/src/share/vm/runtime/vframe.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/runtime/vframe.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -402,7 +402,12 @@ DebugInfoReadStream buffer(nm(), decode_offset); _sender_decode_offset = buffer.read_int(); _method = methodOop(buffer.read_oop()); - _bci = buffer.read_bci(); + // Deoptimization needs reexecute bit to determine whether to reexecute the bytecode + // only at the time when it "unpack_frames", and the reexecute bit info could always + // be obtained from the scopeDesc in the compiledVFrame. As a result, we don't keep + // the reexecute bit here. + bool dummy_reexecute; + _bci = buffer.read_bci_and_reexecute(dummy_reexecute); assert(_method->is_method(), "checking type of decoded method"); } diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/runtime/vframeArray.cpp --- a/hotspot/src/share/vm/runtime/vframeArray.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/runtime/vframeArray.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -44,6 +44,7 @@ _method = vf->method(); _bci = vf->raw_bci(); + _reexecute = vf->should_reexecute(); int index; @@ -148,16 +149,20 @@ // C++ interpreter doesn't need a pc since it will figure out what to do when it // begins execution address pc; - bool use_next_mdp; // true if we should use the mdp associated with the next bci - // rather than the one associated with bcp + bool use_next_mdp = false; // true if we should use the mdp associated with the next bci + // rather than the one associated with bcp if (raw_bci() == SynchronizationEntryBCI) { // We are deoptimizing while hanging in prologue code for synchronized method bcp = method()->bcp_from(0); // first byte code pc = Interpreter::deopt_entry(vtos, 0); // step = 0 since we don't skip current bytecode - use_next_mdp = false; + } else if (should_reexecute()) { //reexecute this bytecode + assert(is_top_frame, "reexecute allowed only for the top frame"); + bcp = method()->bcp_from(bci()); + pc = Interpreter::deopt_reexecute_entry(method(), bcp); } else { bcp = method()->bcp_from(bci()); - pc = Interpreter::continuation_for(method(), bcp, callee_parameters, is_top_frame, use_next_mdp); + pc = Interpreter::deopt_continue_after_entry(method(), bcp, callee_parameters, is_top_frame); + use_next_mdp = true; } assert(Bytecodes::is_defined(*bcp), "must be a valid bytecode"); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/runtime/vframeArray.hpp --- a/hotspot/src/share/vm/runtime/vframeArray.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/runtime/vframeArray.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -41,7 +41,8 @@ private: frame _frame; // the interpreter frame we will unpack into - int _bci; // raw bci for this vframe + int _bci; // raw bci for this vframe + bool _reexecute; // whether sould we reexecute this bytecode methodOop _method; // the method for this vframe MonitorChunk* _monitors; // active monitors for this vframe StackValueCollection* _locals; @@ -54,6 +55,7 @@ int bci(void) const; int raw_bci(void) const { return _bci; } + bool should_reexecute(void) const { return _reexecute; } methodOop method(void) const { return _method; } diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/runtime/vframe_hp.cpp --- a/hotspot/src/share/vm/runtime/vframe_hp.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/runtime/vframe_hp.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -276,6 +276,15 @@ return scope()->bci(); } +bool compiledVFrame::should_reexecute() const { + if (scope() == NULL) { + // native nmethods have no scope the method/bci is implied + nmethod* nm = code(); + assert(nm->is_native_method(), "must be native"); + return false; + } + return scope()->should_reexecute(); +} vframe* compiledVFrame::sender() const { const frame f = fr(); diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/runtime/vframe_hp.hpp --- a/hotspot/src/share/vm/runtime/vframe_hp.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/runtime/vframe_hp.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -25,11 +25,12 @@ class compiledVFrame: public javaVFrame { public: // JVM state - methodOop method() const; - int bci() const; - StackValueCollection* locals() const; - StackValueCollection* expressions() const; - GrowableArray* monitors() const; + methodOop method() const; + int bci() const; + bool should_reexecute() const; + StackValueCollection* locals() const; + StackValueCollection* expressions() const; + GrowableArray* monitors() const; void set_locals(StackValueCollection* values) const; diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/services/threadService.cpp --- a/hotspot/src/share/vm/services/threadService.cpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/services/threadService.cpp Wed Jul 05 16:59:43 2017 +0200 @@ -688,10 +688,9 @@ _contended_enter_count = 0; _monitor_wait_count = 0; _sleep_count = 0; - _class_init_recursion_count = 0; - _class_verify_recursion_count = 0; _count_pending_reset = false; _timer_pending_reset = false; + memset((void*) _perf_recursion_counts, 0, sizeof(_perf_recursion_counts)); } ThreadSnapshot::ThreadSnapshot(JavaThread* thread) { diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/services/threadService.hpp --- a/hotspot/src/share/vm/services/threadService.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/services/threadService.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -120,9 +120,8 @@ bool _timer_pending_reset; // Keep accurate times for potentially recursive class operations - int _class_init_recursion_count; - int _class_verify_recursion_count; - int _class_link_recursion_count; + int _perf_recursion_counts[6]; + elapsedTimer _perf_timers[6]; // utility functions void check_and_reset_count() { @@ -165,9 +164,8 @@ void reset_count_stat() { _count_pending_reset = true; } void reset_time_stat() { _timer_pending_reset = true; } - int* class_init_recursion_count_addr() { return &_class_init_recursion_count; } - int* class_verify_recursion_count_addr() { return &_class_verify_recursion_count; } - int* class_link_recursion_count_addr() { return &_class_link_recursion_count; } + int* perf_recursion_counts_addr() { return _perf_recursion_counts; } + elapsedTimer* perf_timers_addr() { return _perf_timers; } }; // Thread snapshot to represent the thread state and statistics diff -r ae9b655e7393 -r e17115919cc7 hotspot/src/share/vm/utilities/taskqueue.hpp --- a/hotspot/src/share/vm/utilities/taskqueue.hpp Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/src/share/vm/utilities/taskqueue.hpp Wed Jul 05 16:59:43 2017 +0200 @@ -22,94 +22,90 @@ * */ -#ifdef LP64 -typedef juint TAG_TYPE; -// for a taskqueue size of 4M -#define LOG_TASKQ_SIZE 22 -#else -typedef jushort TAG_TYPE; -// for a taskqueue size of 16K -#define LOG_TASKQ_SIZE 14 -#endif - class TaskQueueSuper: public CHeapObj { protected: - // The first free element after the last one pushed (mod _n). + // Internal type for indexing the queue; also used for the tag. + typedef NOT_LP64(uint16_t) LP64_ONLY(uint32_t) idx_t; + + // The first free element after the last one pushed (mod N). volatile uint _bottom; - // log2 of the size of the queue. - enum SomeProtectedConstants { - Log_n = LOG_TASKQ_SIZE + enum { + N = 1 << NOT_LP64(14) LP64_ONLY(17), // Queue size: 16K or 128K + MOD_N_MASK = N - 1 // To compute x mod N efficiently. }; -#undef LOG_TASKQ_SIZE + + class Age { + public: + Age(size_t data = 0) { _data = data; } + Age(const Age& age) { _data = age._data; } + Age(idx_t top, idx_t tag) { _fields._top = top; _fields._tag = tag; } - // Size of the queue. - uint n() { return (1 << Log_n); } - // For computing "x mod n" efficiently. - uint n_mod_mask() { return n() - 1; } + Age get() const volatile { return _data; } + void set(Age age) volatile { _data = age._data; } + + idx_t top() const volatile { return _fields._top; } + idx_t tag() const volatile { return _fields._tag; } - struct Age { - TAG_TYPE _top; - TAG_TYPE _tag; + // Increment top; if it wraps, increment tag also. + void increment() { + _fields._top = increment_index(_fields._top); + if (_fields._top == 0) ++_fields._tag; + } - TAG_TYPE tag() const { return _tag; } - TAG_TYPE top() const { return _top; } + Age cmpxchg(const Age new_age, const Age old_age) volatile { + return (size_t) Atomic::cmpxchg_ptr((intptr_t)new_age._data, + (volatile intptr_t *)&_data, + (intptr_t)old_age._data); + } + + bool operator ==(const Age& other) const { return _data == other._data; } - Age() { _tag = 0; _top = 0; } - - friend bool operator ==(const Age& a1, const Age& a2) { - return a1.tag() == a2.tag() && a1.top() == a2.top(); - } + private: + struct fields { + idx_t _top; + idx_t _tag; + }; + union { + size_t _data; + fields _fields; + }; }; - Age _age; - // These make sure we do single atomic reads and writes. - Age get_age() { - uint res = *(volatile uint*)(&_age); - return *(Age*)(&res); + + volatile Age _age; + + // These both operate mod N. + static uint increment_index(uint ind) { + return (ind + 1) & MOD_N_MASK; } - void set_age(Age a) { - *(volatile uint*)(&_age) = *(uint*)(&a); + static uint decrement_index(uint ind) { + return (ind - 1) & MOD_N_MASK; } - TAG_TYPE get_top() { - return get_age().top(); - } - - // These both operate mod _n. - uint increment_index(uint ind) { - return (ind + 1) & n_mod_mask(); - } - uint decrement_index(uint ind) { - return (ind - 1) & n_mod_mask(); - } - - // Returns a number in the range [0.._n). If the result is "n-1", it - // should be interpreted as 0. + // Returns a number in the range [0..N). If the result is "N-1", it should be + // interpreted as 0. uint dirty_size(uint bot, uint top) { - return ((int)bot - (int)top) & n_mod_mask(); + return (bot - top) & MOD_N_MASK; } // Returns the size corresponding to the given "bot" and "top". uint size(uint bot, uint top) { uint sz = dirty_size(bot, top); - // Has the queue "wrapped", so that bottom is less than top? - // There's a complicated special case here. A pair of threads could - // perform pop_local and pop_global operations concurrently, starting - // from a state in which _bottom == _top+1. The pop_local could - // succeed in decrementing _bottom, and the pop_global in incrementing - // _top (in which case the pop_global will be awarded the contested - // queue element.) The resulting state must be interpreted as an empty - // queue. (We only need to worry about one such event: only the queue - // owner performs pop_local's, and several concurrent threads - // attempting to perform the pop_global will all perform the same CAS, - // and only one can succeed. Any stealing thread that reads after - // either the increment or decrement will see an empty queue, and will - // not join the competitors. The "sz == -1 || sz == _n-1" state will - // not be modified by concurrent queues, so the owner thread can reset - // the state to _bottom == top so subsequent pushes will be performed - // normally. - if (sz == (n()-1)) return 0; - else return sz; + // Has the queue "wrapped", so that bottom is less than top? There's a + // complicated special case here. A pair of threads could perform pop_local + // and pop_global operations concurrently, starting from a state in which + // _bottom == _top+1. The pop_local could succeed in decrementing _bottom, + // and the pop_global in incrementing _top (in which case the pop_global + // will be awarded the contested queue element.) The resulting state must + // be interpreted as an empty queue. (We only need to worry about one such + // event: only the queue owner performs pop_local's, and several concurrent + // threads attempting to perform the pop_global will all perform the same + // CAS, and only one can succeed.) Any stealing thread that reads after + // either the increment or decrement will see an empty queue, and will not + // join the competitors. The "sz == -1 || sz == N-1" state will not be + // modified by concurrent queues, so the owner thread can reset the state to + // _bottom == top so subsequent pushes will be performed normally. + return (sz == N - 1) ? 0 : sz; } public: @@ -122,22 +118,21 @@ // The "careful" version admits the possibility of pop_local/pop_global // races. uint size() { - return size(_bottom, get_top()); + return size(_bottom, _age.top()); } uint dirty_size() { - return dirty_size(_bottom, get_top()); + return dirty_size(_bottom, _age.top()); } void set_empty() { _bottom = 0; - _age = Age(); + _age.set(0); } // Maximum number of elements allowed in the queue. This is two less // than the actual queue size, for somewhat complicated reasons. - uint max_elems() { return n() - 2; } - + uint max_elems() { return N - 2; } }; template class GenericTaskQueue: public TaskQueueSuper { @@ -179,12 +174,12 @@ template GenericTaskQueue::GenericTaskQueue():TaskQueueSuper() { - assert(sizeof(Age) == sizeof(int), "Depends on this."); + assert(sizeof(Age) == sizeof(size_t), "Depends on this."); } template void GenericTaskQueue::initialize() { - _elems = NEW_C_HEAP_ARRAY(E, n()); + _elems = NEW_C_HEAP_ARRAY(E, N); guarantee(_elems != NULL, "Allocation failed."); } @@ -208,14 +203,14 @@ template bool GenericTaskQueue::push_slow(E t, uint dirty_n_elems) { - if (dirty_n_elems == n() - 1) { + if (dirty_n_elems == N - 1) { // Actually means 0, so do the push. uint localBot = _bottom; _elems[localBot] = t; _bottom = increment_index(localBot); return true; - } else - return false; + } + return false; } template @@ -230,53 +225,45 @@ // then have the owner thread do a pop followed by another push. Without // the incrementing of "tag", the pop_global's CAS could succeed, // allowing it to believe it has claimed the stale element.) - Age newAge; - newAge._top = localBot; - newAge._tag = oldAge.tag() + 1; + Age newAge((idx_t)localBot, oldAge.tag() + 1); // Perhaps a competing pop_global has already incremented "top", in which // case it wins the element. if (localBot == oldAge.top()) { - Age tempAge; // No competing pop_global has yet incremented "top"; we'll try to // install new_age, thus claiming the element. - assert(sizeof(Age) == sizeof(int), "Assumption about CAS unit."); - *(uint*)&tempAge = Atomic::cmpxchg(*(uint*)&newAge, (volatile uint*)&_age, *(uint*)&oldAge); + Age tempAge = _age.cmpxchg(newAge, oldAge); if (tempAge == oldAge) { // We win. - assert(dirty_size(localBot, get_top()) != n() - 1, - "Shouldn't be possible..."); + assert(dirty_size(localBot, _age.top()) != N - 1, "sanity"); return true; } } - // We fail; a completing pop_global gets the element. But the queue is - // empty (and top is greater than bottom.) Fix this representation of - // the empty queue to become the canonical one. - set_age(newAge); - assert(dirty_size(localBot, get_top()) != n() - 1, - "Shouldn't be possible..."); + // We lose; a completing pop_global gets the element. But the queue is empty + // and top is greater than bottom. Fix this representation of the empty queue + // to become the canonical one. + _age.set(newAge); + assert(dirty_size(localBot, _age.top()) != N - 1, "sanity"); return false; } template bool GenericTaskQueue::pop_global(E& t) { - Age newAge; - Age oldAge = get_age(); + Age oldAge = _age.get(); uint localBot = _bottom; uint n_elems = size(localBot, oldAge.top()); if (n_elems == 0) { return false; } + t = _elems[oldAge.top()]; - newAge = oldAge; - newAge._top = increment_index(newAge.top()); - if ( newAge._top == 0 ) newAge._tag++; - Age resAge; - *(uint*)&resAge = Atomic::cmpxchg(*(uint*)&newAge, (volatile uint*)&_age, *(uint*)&oldAge); + Age newAge(oldAge); + newAge.increment(); + Age resAge = _age.cmpxchg(newAge, oldAge); + // Note that using "_bottom" here might fail, since a pop_local might // have decremented it. - assert(dirty_size(localBot, newAge._top) != n() - 1, - "Shouldn't be possible..."); - return (resAge == oldAge); + assert(dirty_size(localBot, newAge.top()) != N - 1, "sanity"); + return resAge == oldAge; } template @@ -459,7 +446,7 @@ return offer_termination(NULL); } - // As above, but it also terminates of the should_exit_termination() + // As above, but it also terminates if the should_exit_termination() // method of the terminator parameter returns true. If terminator is // NULL, then it is ignored. bool offer_termination(TerminatorTerminator* terminator); @@ -492,11 +479,10 @@ } #else uint localBot = _bottom; - assert((localBot >= 0) && (localBot < n()), "_bottom out of range."); - TAG_TYPE top = get_top(); + assert((localBot >= 0) && (localBot < N), "_bottom out of range."); + idx_t top = _age.top(); uint dirty_n_elems = dirty_size(localBot, top); - assert((dirty_n_elems >= 0) && (dirty_n_elems < n()), - "n_elems out of range."); + assert((dirty_n_elems >= 0) && (dirty_n_elems < N), "n_elems out of range."); if (dirty_n_elems < max_elems()) { _elems[localBot] = t; _bottom = increment_index(localBot); @@ -517,12 +503,12 @@ return true; #else uint localBot = _bottom; - // This value cannot be n-1. That can only occur as a result of + // This value cannot be N-1. That can only occur as a result of // the assignment to bottom in this method. If it does, this method // resets the size( to 0 before the next call (which is sequential, // since this is pop_local.) - uint dirty_n_elems = dirty_size(localBot, get_top()); - assert(dirty_n_elems != n() - 1, "Shouldn't be possible..."); + uint dirty_n_elems = dirty_size(localBot, _age.top()); + assert(dirty_n_elems != N - 1, "Shouldn't be possible..."); if (dirty_n_elems == 0) return false; localBot = decrement_index(localBot); _bottom = localBot; @@ -534,15 +520,14 @@ // If there's still at least one element in the queue, based on the // "_bottom" and "age" we've read, then there can be no interference with // a "pop_global" operation, and we're done. - TAG_TYPE tp = get_top(); // XXX + idx_t tp = _age.top(); // XXX if (size(localBot, tp) > 0) { - assert(dirty_size(localBot, tp) != n() - 1, - "Shouldn't be possible..."); + assert(dirty_size(localBot, tp) != N - 1, "sanity"); return true; } else { // Otherwise, the queue contained exactly one element; we take the slow // path. - return pop_local_slow(localBot, get_age()); + return pop_local_slow(localBot, _age.get()); } #endif } diff -r ae9b655e7393 -r e17115919cc7 hotspot/test/compiler/6826736/Test.java --- a/hotspot/test/compiler/6826736/Test.java Tue Sep 01 23:44:41 2009 +0100 +++ b/hotspot/test/compiler/6826736/Test.java Wed Jul 05 16:59:43 2017 +0200 @@ -27,7 +27,7 @@ * @bug 6826736 * @summary CMS: core dump with -XX:+UseCompressedOops * - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch -XX:+ScavengeALot -XX:+UseCompressedOops -XX:HeapBaseMinAddress=32g -XX:CompileThreshold=100 -XX:CompileOnly=Test.test -XX:-BlockLayoutRotateLoops -XX:LoopUnrollLimit=0 Test + * @run main/othervm/timeout=600 -XX:+IgnoreUnrecognizedVMOptions -Xbatch -XX:+ScavengeALot -XX:+UseCompressedOops -XX:HeapBaseMinAddress=32g -XX:CompileThreshold=100 -XX:CompileOnly=Test.test -XX:-BlockLayoutRotateLoops -XX:LoopUnrollLimit=0 Test */ public class Test { diff -r ae9b655e7393 -r e17115919cc7 hotspot/test/compiler/6833129/Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/6833129/Test.java Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6833129 + * @summary Object.clone() and Arrays.copyOf ignore coping with -XX:+DeoptimizeALot + * @run main/othervm -Xbatch -XX:+DeoptimizeALot Test + */ + +public class Test{ + public static void init(int src[]) { + for (int i =0; i { + protected static final int DEFAULT_INITIAL_CAPACITY = 16; + private static final int MAXIMUM_CAPACITY = 1 << 30; + private static final float DEFAULT_LOAD_FACTOR = 0.75f; + + protected Entry[] table; + + private int size; + protected int threshold; + private final float loadFactor; + private final ReferenceQueue queue = new ReferenceQueue(); + + public WeakPool() + { + this.loadFactor = DEFAULT_LOAD_FACTOR; + threshold = DEFAULT_INITIAL_CAPACITY; + table = new Entry[DEFAULT_INITIAL_CAPACITY]; + } + + /** + * Check for equality of non-null reference x and possibly-null y. By + * default uses Object.equals. + */ + private boolean eq(Object x, Object y) + { + return x == y || x.equals(y); + } + + /** + * Return index for hash code h. + */ + private int indexFor(int h, int length) + { + return h & length - 1; + } + + /** + * Expunge stale entries from the table. + */ + private void expungeStaleEntries() + { + Object r; + while ((r = queue.poll()) != null) + { + Entry e = (Entry) r; + int h = e.hash; + int i = indexFor(h, table.length); + + // System.out.println("EXPUNGING " + h); + Entry prev = table[i]; + Entry p = prev; + while (p != null) + { + Entry next = p.next; + if (p == e) + { + if (prev == e) + { + table[i] = next; + } + else + { + prev.next = next; + } + e.next = null; // Help GC + size--; + break; + } + prev = p; + p = next; + } + } + } + + /** + * Return the table after first expunging stale entries + */ + private Entry[] getTable() + { + expungeStaleEntries(); + return table; + } + + /** + * Returns the number of key-value mappings in this map. + * This result is a snapshot, and may not reflect unprocessed + * entries that will be removed before next attempted access + * because they are no longer referenced. + */ + public int size() + { + if (size == 0) + { + return 0; + } + expungeStaleEntries(); + return size; + } + + /** + * Returns true if this map contains no key-value mappings. + * This result is a snapshot, and may not reflect unprocessed + * entries that will be removed before next attempted access + * because they are no longer referenced. + */ + public boolean isEmpty() + { + return size() == 0; + } + + /** + * Returns the value stored in the pool that equals the requested key + * or null if the map contains no mapping for + * this key (or the key is null) + * + * @param key the key whose equals value is to be returned. + * @return the object that is equal the specified key, or + * null if key is null or no object in the pool equals the key. + */ + public V get(V key) + { + if (key == null) + { + return null; + } + int h = key.hashCode(); + Entry[] tab = getTable(); + int index = indexFor(h, tab.length); + Entry e = tab[index]; + while (e != null) + { + V candidate = e.get(); + if (e.hash == h && eq(key, candidate)) + { + return candidate; + } + e = e.next; + } + return null; + } + + /** + * Returns the entry associated with the specified key in the HashMap. + * Returns null if the HashMap contains no mapping for this key. + */ + Entry getEntry(Object key) + { + int h = key.hashCode(); + Entry[] tab = getTable(); + int index = indexFor(h, tab.length); + Entry e = tab[index]; + while (e != null && !(e.hash == h && eq(key, e.get()))) + { + e = e.next; + } + return e; + } + + /** + * Places the object into the pool. If the object is null, nothing happens. + * If an equal object already exists, it is not replaced. + * + * @param key the object to put into the pool. key may be null. + * @return the object in the pool that is equal to the key, or the newly placed key if no such object existed when put was called + */ + public V put(V key) + { + if (key == null) + { + return null; + } + int h = key.hashCode(); + Entry[] tab = getTable(); + int i = indexFor(h, tab.length); + + for (Entry e = tab[i]; e != null; e = e.next) + { + V candidate = e.get(); + if (h == e.hash && eq(key, candidate)) + { + return candidate; + } + } + + tab[i] = new Entry(key, queue, h, tab[i]); + + if (++size >= threshold) + { + resize(tab.length * 2); + } + + // System.out.println("Added " + key + " to pool"); + return key; + } + + /** + * Rehashes the contents of this map into a new array with a + * larger capacity. This method is called automatically when the + * number of keys in this map reaches its threshold. + *

+ * If current capacity is MAXIMUM_CAPACITY, this method does not + * resize the map, but but sets threshold to Integer.MAX_VALUE. + * This has the effect of preventing future calls. + * + * @param newCapacity the new capacity, MUST be a power of two; + * must be greater than current capacity unless current + * capacity is MAXIMUM_CAPACITY (in which case value + * is irrelevant). + */ + void resize(int newCapacity) + { + Entry[] oldTable = getTable(); + int oldCapacity = oldTable.length; + if (oldCapacity == MAXIMUM_CAPACITY) + { + threshold = Integer.MAX_VALUE; + return; + } + + Entry[] newTable = new Entry[newCapacity]; + transfer(oldTable, newTable); + table = newTable; + + /* + * If ignoring null elements and processing ref queue caused massive + * shrinkage, then restore old table. This should be rare, but avoids + * unbounded expansion of garbage-filled tables. + */ + if (size >= threshold / 2) + { + threshold = (int) (newCapacity * loadFactor); + } + else + { + expungeStaleEntries(); + transfer(newTable, oldTable); + table = oldTable; + } + } + + /** + * Transfer all entries from src to dest tables + */ + private void transfer(Entry[] src, Entry[] dest) + { + for (int j = 0; j < src.length; ++j) + { + Entry e = src[j]; + src[j] = null; + while (e != null) + { + Entry next = e.next; + Object key = e.get(); + if (key == null) + { + e.next = null; // Help GC + size--; + } + else + { + int i = indexFor(e.hash, dest.length); + e.next = dest[i]; + dest[i] = e; + } + e = next; + } + } + } + + /** + * Removes the object in the pool that equals the key. + * + * @param key + * @return previous value associated with specified key, or null + * if there was no mapping for key or the key is null. + */ + public V removeFromPool(V key) + { + if (key == null) + { + return null; + } + int h = key.hashCode(); + Entry[] tab = getTable(); + int i = indexFor(h, tab.length); + Entry prev = tab[i]; + Entry e = prev; + + while (e != null) + { + Entry next = e.next; + V candidate = e.get(); + if (h == e.hash && eq(key, candidate)) + { + size--; + if (prev == e) + { + tab[i] = next; + } + else + { + prev.next = next; + } + return candidate; + } + prev = e; + e = next; + } + + return null; + } + + /** + * Removes all mappings from this map. + */ + public void clear() + { + // clear out ref queue. We don't need to expunge entries + // since table is getting cleared. + while (queue.poll() != null) + { + // nop + } + + table = new Entry[DEFAULT_INITIAL_CAPACITY]; + threshold = DEFAULT_INITIAL_CAPACITY; + size = 0; + + // Allocation of array may have caused GC, which may have caused + // additional entries to go stale. Removing these entries from the + // reference queue will make them eligible for reclamation. + while (queue.poll() != null) + { + // nop + } + } + + /** + * The entries in this hash table extend WeakReference, using its main ref + * field as the key. + */ + protected static class Entry + extends WeakReference + { + private final int hash; + private Entry next; + + /** + * Create new entry. + */ + Entry(final V key, final ReferenceQueue queue, final int hash, final Entry next) + { + super(key, queue); + this.hash = hash; + this.next = next; + } + + public V getKey() + { + return super.get(); + } + + public boolean equals(Object o) + { + if (!(o instanceof WeakPool.Entry)) + { + return false; + } + WeakPool.Entry that = (WeakPool.Entry) o; + V k1 = this.getKey(); + V k2 = that.getKey(); + return (k1==k2 || k1.equals(k2)); + } + + public int hashCode() + { + return this.hash; + } + + public String toString() + { + return String.valueOf(this.getKey()); + } + } +} + +final class MultiSynonymKey { + private List keys; + + public MultiSynonymKey() { + keys = new ArrayList(); + } + + public MultiSynonymKey(MyList... arg) { + keys = Arrays.asList(arg); + } + + public List getKeys() { + return keys; + } + + public int hashCode() { + return this.getKeys().hashCode(); + } + + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (!(obj instanceof MultiSynonymKey)) { + return false; + } + + MultiSynonymKey that = (MultiSynonymKey) obj; + return this.getKeys().equals(that.getKeys()); + } + + public String toString() { + return this.getClass().getName() + this.getKeys().toString(); + } +} + +public class Test extends Thread { + static public Test test; + static private byte[] arg1; + static private byte[] arg2; + static public WeakPool wp; + public volatile MultiSynonymKey ml1; + public volatile MultiSynonymKey ml2; + private volatile MultiSynonymKey ml3; + + public void run() { + int count=0; + while (true) { + try { + Thread.sleep(10); + } catch (Exception e) {} + synchronized (wp) { + ml2 = new MultiSynonymKey(new DoubletonList(new String(arg1), new String(arg2))); + wp.put(ml2); + ml3 = new MultiSynonymKey(new DoubletonList(new String(arg1), new String(arg2))); + } + try { + Thread.sleep(10); + } catch (Exception e) {} + synchronized (wp) { + ml1 = new MultiSynonymKey(new SingletonList(new String(arg1))); + wp.put(ml1); + ml3 = new MultiSynonymKey(new SingletonList(new String(arg1))); + } + if (count++==100) + System.exit(95); + } + } + + public static void main(String[] args) throws Exception { + wp = new WeakPool(); + test = new Test(); + + test.arg1 = args[0].getBytes(); + test.arg2 = args[1].getBytes(); + + test.ml1 = new MultiSynonymKey(new SingletonList(new String(test.arg1))); + test.ml2 = new MultiSynonymKey(new DoubletonList(new String(test.arg1), new String(test.arg2))); + test.ml3 = new MultiSynonymKey(new DoubletonList(new String(test.arg1), new String(test.arg2))); + + wp.put(test.ml1); + wp.put(test.ml2); + + test.setDaemon(true); + test.start(); + + int counter = 0; + while (true) { + synchronized (wp) { + MultiSynonymKey foo = test.ml3; + + if (wp.put(foo) == foo) { + // System.out.println("foo " + counter); + // System.out.println(foo); + } + } + counter++; + } + } + + private boolean eq(Object x, Object y) { + return x == y || x.equals(y); + } +} diff -r ae9b655e7393 -r e17115919cc7 jdk/.hgignore --- a/jdk/.hgignore Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/.hgignore Wed Jul 05 16:59:43 2017 +0200 @@ -1,3 +1,6 @@ ^build/ ^dist/ ^nbproject/private/ +^make/netbeans/.*/nbproject/private/ +^make/netbeans/.*/build/ +^make/netbeans/.*/dist/ diff -r ae9b655e7393 -r e17115919cc7 jdk/.hgtags --- a/jdk/.hgtags Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/.hgtags Wed Jul 05 16:59:43 2017 +0200 @@ -44,3 +44,4 @@ a952aafd5181af953b0ef3010dbd2fcc28460e8a jdk7-b67 b23d905cb5d3b382295240d28ab0bfb266b4503c jdk7-b68 226b20019b1f020c09ea97d137d98e011ce65d76 jdk7-b69 +893bcca951b747ddcf6986362b877f0e1dbb835b jdk7-b70 diff -r ae9b655e7393 -r e17115919cc7 jdk/make/common/shared/Defs-java.gmk --- a/jdk/make/common/shared/Defs-java.gmk Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/make/common/shared/Defs-java.gmk Wed Jul 05 16:59:43 2017 +0200 @@ -201,7 +201,10 @@ ifeq ($(JAVAC_WARNINGS_FATAL), true) BOOT_JAVACFLAGS += -Werror endif -BOOT_JAVACFLAGS += -encoding ascii + +BOOT_SOURCE_LANGUAGE_VERSION = 6 +BOOT_TARGET_CLASS_VERSION = 6 +BOOT_JAVACFLAGS += -encoding ascii -source $(BOOT_SOURCE_LANGUAGE_VERSION) -target $(BOOT_TARGET_CLASS_VERSION) BOOT_JAR_JFLAGS += $(JAR_JFLAGS) BOOT_JAVACFLAGS += $(NO_PROPRIETARY_API_WARNINGS) diff -r ae9b655e7393 -r e17115919cc7 jdk/make/java/nio/FILES_java.gmk --- a/jdk/make/java/nio/FILES_java.gmk Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/make/java/nio/FILES_java.gmk Wed Jul 05 16:59:43 2017 +0200 @@ -160,7 +160,6 @@ \ sun/nio/ByteBuffered.java \ \ - sun/nio/ch/AbstractFuture.java \ sun/nio/ch/AbstractPollArrayWrapper.java \ sun/nio/ch/AllocatedNativeObject.java \ sun/nio/ch/AsynchronousChannelGroupImpl.java \ diff -r ae9b655e7393 -r e17115919cc7 jdk/make/netbeans/jdwpgen/build.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/netbeans/jdwpgen/build.xml Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,74 @@ + + + + + + + + + + + Builds, tests, and runs the project jdwpgen. + + + diff -r ae9b655e7393 -r e17115919cc7 jdk/make/netbeans/jdwpgen/nbproject/build-impl.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/netbeans/jdwpgen/nbproject/build-impl.xml Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,642 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + + + + + + java -cp "${run.classpath.with.dist.jar}" ${main.class} + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + diff -r ae9b655e7393 -r e17115919cc7 jdk/make/netbeans/jdwpgen/nbproject/findbugs.settings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/netbeans/jdwpgen/nbproject/findbugs.settings Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,72 @@ +#FindBugs User Preferences +#Mon Jun 15 13:37:16 PDT 2009 +detectorAbnormalFinallyBlockReturn=AbnormalFinallyBlockReturn|false +detectorAbstractClassEmptyMethods=AbstractClassEmptyMethods|false +detectorAbstractOverriddenMethod=AbstractOverriddenMethod|false +detectorArrayBasedCollections=ArrayBasedCollections|false +detectorArrayWrappedCallByReference=ArrayWrappedCallByReference|false +detectorBloatedAssignmentScope=BloatedAssignmentScope|false +detectorBloatedSynchronizedBlock=BloatedSynchronizedBlock|false +detectorClassEnvy=ClassEnvy|false +detectorCollectStatistics=CollectStatistics|false +detectorConfusingAutoboxedOverloading=ConfusingAutoboxedOverloading|false +detectorConstantListIndex=ConstantListIndex|false +detectorCopiedOverriddenMethod=CopiedOverriddenMethod|false +detectorCustomBuiltXML=CustomBuiltXML|false +detectorCyclomaticComplexity=CyclomaticComplexity|false +detectorDateComparison=DateComparison|false +detectorDeclaredRuntimeException=DeclaredRuntimeException|false +detectorDeletingWhileIterating=DeletingWhileIterating|false +detectorDubiousListCollection=DubiousListCollection|false +detectorFieldCouldBeLocal=FieldCouldBeLocal|false +detectorFinalParameters=FinalParameters|false +detectorFloatingPointLoops=FloatingPointLoops|false +detectorInefficientStringBuffering=InefficientStringBuffering|false +detectorInheritanceTypeChecking=InheritanceTypeChecking|false +detectorJDBCVendorReliance=JDBCVendorReliance|false +detectorListIndexedIterating=ListIndexedIterating|false +detectorLiteralStringComparison=LiteralStringComparison|false +detectorLocalSynchronizedCollection=LocalSynchronizedCollection|false +detectorLostExceptionStackTrace=LostExceptionStackTrace|false +detectorManualArrayCopy=ManualArrayCopy|false +detectorMethodReturnsConstant=MethodReturnsConstant|false +detectorNeedlessAutoboxing=NeedlessAutoboxing|false +detectorNeedlessCustomSerialization=NeedlessCustomSerialization|false +detectorNeedlessInstanceRetrieval=NeedlessInstanceRetrieval|false +detectorNeedlessMemberCollectionSynchronization=NeedlessMemberCollectionSynchronization|false +detectorNonCollectionMethodUse=NonCollectionMethodUse|false +detectorNonOwnedSynchronization=NonOwnedSynchronization|false +detectorNonRecycleableTaglibs=NonRecycleableTaglibs|false +detectorOrphanedDOMNode=OrphanedDOMNode|false +detectorOverlyConcreteParameter=OverlyConcreteParameter|false +detectorParallelLists=ParallelLists|false +detectorPartiallyConstructedObjectAccess=PartiallyConstructedObjectAccess|false +detectorPossibleIncompleteSerialization=PossibleIncompleteSerialization|false +detectorPossibleMemoryBloat=PossibleMemoryBloat|false +detectorPossiblyRedundantMethodCalls=PossiblyRedundantMethodCalls|false +detectorSQLInLoop=SQLInLoop|false +detectorSection508Compliance=Section508Compliance|false +detectorSillynessPotPourri=SillynessPotPourri|false +detectorSloppyClassReflection=SloppyClassReflection|false +detectorSluggishGui=SluggishGui|false +detectorSpoiledChildInterfaceImplementor=SpoiledChildInterfaceImplementor|false +detectorSpuriousThreadStates=SpuriousThreadStates|false +detectorStaticArrayCreatedInMethod=StaticArrayCreatedInMethod|false +detectorStaticMethodInstanceInvocation=StaticMethodInstanceInvocation|false +detectorSuspiciousComparatorReturnValues=SuspiciousComparatorReturnValues|false +detectorSuspiciousJDKVersionUse=SuspiciousJDKVersionUse|false +detectorSuspiciousWaitOnConcurrentObject=SuspiciousWaitOnConcurrentObject|false +detectorSyncCollectionIterators=SyncCollectionIterators|false +detectorTailRecursion=TailRecursion|false +detectorUnnecessaryStoreBeforeReturn=UnnecessaryStoreBeforeReturn|false +detectorUnrelatedCollectionContents=UnrelatedCollectionContents|false +detectorUnrelatedReturnValues=UnrelatedReturnValues|false +detectorUseAddAll=UseAddAll|false +detectorUseCharacterParameterizedMethod=UseCharacterParameterizedMethod|false +detectorUseEnumCollections=UseEnumCollections|false +detectorUseSplit=UseSplit|false +detectorUseToArray=UseToArray|false +detector_threshold=2 +effort=default +filter_settings=Medium|BAD_PRACTICE,CORRECTNESS,I18N,MALICIOUS_CODE,MT_CORRECTNESS,PERFORMANCE,SECURITY,STYLE|false +filter_settings_neg=| diff -r ae9b655e7393 -r e17115919cc7 jdk/make/netbeans/jdwpgen/nbproject/genfiles.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/netbeans/jdwpgen/nbproject/genfiles.properties Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,8 @@ +build.xml.data.CRC32=b40e775f +build.xml.script.CRC32=af8dc3cb +build.xml.stylesheet.CRC32=958a1d3e +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=b40e775f +nbproject/build-impl.xml.script.CRC32=624d12c5 +nbproject/build-impl.xml.stylesheet.CRC32=65b8de21 diff -r ae9b655e7393 -r e17115919cc7 jdk/make/netbeans/jdwpgen/nbproject/project.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/netbeans/jdwpgen/nbproject/project.properties Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,65 @@ +application.title=jdwpgen +application.vendor=sun +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/jdwpgen.jar +dist.javadoc.dir=${dist.dir}/javadoc +excludes= +file.reference.tools-jdwpgen=../../tools/src/build/tools/jdwpgen +file.reference.tools-src=../../tools/src +includes=build/tools/jdwpgen/** +jar.compress=false +javac.classpath= +# Space-separated list of extra javac options +javac.compilerargs=-Xlint:all +javac.deprecation=false +javac.source=1.5 +javac.target=1.5 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir}:\ + ${libs.junit.classpath}:\ + ${libs.junit_4.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=true +javadoc.nonavbar=true +javadoc.notree=true +javadoc.private=true +javadoc.splitindex=false +javadoc.use=false +javadoc.version=false +javadoc.windowtitle= +main.class=jdwpgen.Main +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value +# or test-sys-prop.name=value to set system properties for unit tests): +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.src.dir=${file.reference.tools-src} +test.src.dir=test diff -r ae9b655e7393 -r e17115919cc7 jdk/make/netbeans/jdwpgen/nbproject/project.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/netbeans/jdwpgen/nbproject/project.xml Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,16 @@ + + + org.netbeans.modules.java.j2seproject + + + jdwpgen + 1.6.5 + + + + + + + + + diff -r ae9b655e7393 -r e17115919cc7 jdk/make/netbeans/jdwpgen/nbproject/sqe.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/netbeans/jdwpgen/nbproject/sqe.properties Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,2 @@ +#Path to FindbugsSettingsFile (relative) +findbugs.settings.file=findbugs.settings diff -r ae9b655e7393 -r e17115919cc7 jdk/make/tools/freetypecheck/Makefile --- a/jdk/make/tools/freetypecheck/Makefile Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/make/tools/freetypecheck/Makefile Wed Jul 05 16:59:43 2017 +0200 @@ -28,16 +28,21 @@ include $(BUILDDIR)/common/Defs.gmk # Default name -FT_TEST = $(BUILDTOOLBINDIR)/freetype_versioncheck$(EXE_SUFFIX) +PROGRAM = freetype_versioncheck +FT_OBJ = $(BUILDTOOLBINDIR)/$(PROGRAM).$(OBJECT_SUFFIX) +FT_TEST = $(BUILDTOOLBINDIR)/$(PROGRAM)$(EXE_SUFFIX) # Used on openjdk only ifeq ($(OPENJDK),true) # Start with CFLAGS (which gets us the required -xarch setting on solaris) ifeq ($(PLATFORM), windows) - FT_OPTIONS = /nologo $(CC_OBJECT_OUTPUT_FLAG)$(TEMPDIR) + FT_OPTIONS = /nologo /c FREETYPE_DLL = $(FREETYPE_LIB_PATH)/freetype.dll FT_LD_OPTIONS = $(FREETYPE_LIB_PATH)/freetype.lib +ifdef MT + FT_LD_OPTIONS += /manifest +endif else FT_OPTIONS = $(CFLAGS) FT_LD_OPTIONS = -L$(FREETYPE_LIB_PATH) @@ -55,15 +60,22 @@ # Create test program all: $(FT_TEST) - @$(FT_TEST) + $(FT_TEST) # On windows we need to copy dll to test dir to ensure it will be found # at runtime $(FT_TEST): freetypecheck.c - @$(prep-target) + $(prep-target) +ifeq ($(PLATFORM), windows) + $(CC) $(FT_OPTIONS) $(CC_OBJECT_OUTPUT_FLAG)$(FT_OBJ) $< + $(LINK) $(FT_LD_OPTIONS) /OUT:$(FT_TEST) $(FT_OBJ) + $(CP) $(FREETYPE_DLL) $(@D)/ +ifdef MT + $(CP) $(MSVCRNN_DLL_PATH)/$(MSVCRNN_DLL) $(@D)/ + $(MT) /manifest $(FT_TEST).manifest /outputresource:$(FT_TEST);#1 +endif +else @$(CC) $(FT_OPTIONS) $(CC_PROGRAM_OUTPUT_FLAG)$@ $< $(FT_LD_OPTIONS) -ifeq ($(PLATFORM), windows) - @$(CP) $(FREETYPE_DLL) `dirname $@` endif else diff -r ae9b655e7393 -r e17115919cc7 jdk/make/tools/freetypecheck/freetypecheck.c --- a/jdk/make/tools/freetypecheck/freetypecheck.c Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/make/tools/freetypecheck/freetypecheck.c Wed Jul 05 16:59:43 2017 +0200 @@ -32,6 +32,45 @@ #include "ft2build.h" #include FT_FREETYPE_H +#ifdef _MSC_VER +#if _MSC_VER > 1400 + +/* + * When building for Microsoft Windows, your program has a dependency + * on msvcr??.dll. + * + * When using Visual Studio 2005 or later, that must be recorded in + * the .exe.manifest file. + * + * Reference: + * C:/Program Files/Microsoft SDKs/Windows/v6.1/include/crtdefs.h + */ +#include +#ifdef _M_IX86 + +#pragma comment(linker,"/manifestdependency:\"type='win32' " \ + "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".CRT' " \ + "version='" _CRT_ASSEMBLY_VERSION "' " \ + "processorArchitecture='x86' " \ + "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"") + +#endif /* _M_IX86 */ + +//This may not be necessary yet for the Windows 64-bit build, but it +//will be when that build environment is updated. Need to test to see +//if it is harmless: +#ifdef _M_AMD64 + +#pragma comment(linker,"/manifestdependency:\"type='win32' " \ + "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".CRT' " \ + "version='" _CRT_ASSEMBLY_VERSION "' " \ + "processorArchitecture='amd64' " \ + "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"") + +#endif /* _M_AMD64 */ +#endif /* _MSC_VER > 1400 */ +#endif /* _MSC_VER */ + #define QUOTEMACRO(x) QUOTEME(x) #define QUOTEME(x) #x diff -r ae9b655e7393 -r e17115919cc7 jdk/make/tools/src/build/tools/jdwpgen/AbstractNamedNode.java --- a/jdk/make/tools/src/build/tools/jdwpgen/AbstractNamedNode.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/make/tools/src/build/tools/jdwpgen/AbstractNamedNode.java Wed Jul 05 16:59:43 2017 +0200 @@ -30,7 +30,7 @@ abstract class AbstractNamedNode extends Node { - NameNode nameNode; + NameNode nameNode = null; String name; public String name() { diff -r ae9b655e7393 -r e17115919cc7 jdk/make/tools/src/build/tools/jdwpgen/AltNode.java --- a/jdk/make/tools/src/build/tools/jdwpgen/AltNode.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/make/tools/src/build/tools/jdwpgen/AltNode.java Wed Jul 05 16:59:43 2017 +0200 @@ -30,7 +30,7 @@ class AltNode extends AbstractGroupNode implements TypeNode { - SelectNode select; + SelectNode select = null; void constrain(Context ctx) { super.constrain(ctx); diff -r ae9b655e7393 -r e17115919cc7 jdk/make/tools/src/build/tools/jdwpgen/ConstantSetNode.java --- a/jdk/make/tools/src/build/tools/jdwpgen/ConstantSetNode.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/make/tools/src/build/tools/jdwpgen/ConstantSetNode.java Wed Jul 05 16:59:43 2017 +0200 @@ -33,13 +33,7 @@ /** * The mapping between a constant and its value. */ - protected static Map constantMap; - - ConstantSetNode(){ - if (constantMap == null) { - constantMap = new HashMap(); - } - } + protected static final Map constantMap = new HashMap(); void prune() { List addons = new ArrayList(); @@ -95,9 +89,6 @@ } public static String getConstant(String key){ - if (constantMap == null) { - return ""; - } String com = constantMap.get(key); if(com == null){ return ""; diff -r ae9b655e7393 -r e17115919cc7 jdk/make/tools/src/build/tools/jdwpgen/Main.java --- a/jdk/make/tools/src/build/tools/jdwpgen/Main.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/make/tools/src/build/tools/jdwpgen/Main.java Wed Jul 05 16:59:43 2017 +0200 @@ -25,13 +25,11 @@ package build.tools.jdwpgen; -import java.util.*; import java.io.*; class Main { static String specSource; - static Map nameMap = new HashMap(); static boolean genDebug = true; static void usage() { @@ -43,7 +41,6 @@ System.err.println("-doc "); System.err.println("-jdi "); System.err.println("-include "); - System.exit(1); } public static void main(String args[]) throws IOException { @@ -66,6 +63,7 @@ } else { System.err.println("Invalid option: " + arg); usage(); + return; } } else { specSource = arg; @@ -75,6 +73,7 @@ if (reader == null) { System.err.println(" must be specified"); usage(); + return; } Parse parse = new Parse(reader); diff -r ae9b655e7393 -r e17115919cc7 jdk/make/tools/src/build/tools/jdwpgen/Node.java --- a/jdk/make/tools/src/build/tools/jdwpgen/Node.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/make/tools/src/build/tools/jdwpgen/Node.java Wed Jul 05 16:59:43 2017 +0200 @@ -36,7 +36,7 @@ int lineno; List commentList = new ArrayList(); Node parent = null; - Context context; + Context context = null; static final int maxStructIndent = 5; static int structIndent = 0; // horrible hack @@ -82,7 +82,7 @@ } void indent(PrintWriter writer, int depth) { - for (int i = depth; i > 0; --i) { + for (int i = 0; i < depth; i++) { writer.print(" "); } } @@ -195,6 +195,6 @@ System.err.println(Main.specSource + ":" + lineno + ": " + kind + " - " + errmsg); System.err.println(); - System.exit(1); + throw new RuntimeException("Error: " + errmsg); } } diff -r ae9b655e7393 -r e17115919cc7 jdk/make/tools/src/build/tools/jdwpgen/Parse.java --- a/jdk/make/tools/src/build/tools/jdwpgen/Parse.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/make/tools/src/build/tools/jdwpgen/Parse.java Wed Jul 05 16:59:43 2017 +0200 @@ -146,8 +146,12 @@ Node node = (Node)proto.getClass().newInstance(); node.set(kind, list, izer.lineno()); return node; - } catch (Exception exc) { + } catch (InstantiationException exc) { error(exc.toString()); + return null; + } catch (IllegalAccessException exc) { + error(exc.toString()); + return null; } } } else { @@ -166,6 +170,6 @@ void error(String errmsg) { System.err.println(Main.specSource + ":" + izer.lineno() + ": " + errmsg); - System.exit(1); + throw new RuntimeException("Error: " + errmsg); } } diff -r ae9b655e7393 -r e17115919cc7 jdk/make/tools/src/build/tools/jdwpgen/RepeatNode.java --- a/jdk/make/tools/src/build/tools/jdwpgen/RepeatNode.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/make/tools/src/build/tools/jdwpgen/RepeatNode.java Wed Jul 05 16:59:43 2017 +0200 @@ -30,7 +30,7 @@ class RepeatNode extends AbstractTypeNode { - Node member; + Node member = null; void constrain(Context ctx) { super.constrain(ctx); diff -r ae9b655e7393 -r e17115919cc7 jdk/make/tools/src/build/tools/jdwpgen/SelectNode.java --- a/jdk/make/tools/src/build/tools/jdwpgen/SelectNode.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/make/tools/src/build/tools/jdwpgen/SelectNode.java Wed Jul 05 16:59:43 2017 +0200 @@ -30,7 +30,7 @@ class SelectNode extends AbstractGroupNode implements TypeNode { - AbstractSimpleTypeNode typeNode; + AbstractSimpleTypeNode typeNode = null; void prune() { super.prune(); diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/com/sun/security/auth/callback/TextCallbackHandler.java --- a/jdk/src/share/classes/com/sun/security/auth/callback/TextCallbackHandler.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/com/sun/security/auth/callback/TextCallbackHandler.java Wed Jul 05 16:59:43 2017 +0200 @@ -129,7 +129,7 @@ System.err.print(pc.getPrompt()); System.err.flush(); - pc.setPassword(Password.readPassword(System.in)); + pc.setPassword(Password.readPassword(System.in, pc.isEchoOn())); } else if (callbacks[i] instanceof ConfirmationCallback) { confirmation = (ConfirmationCallback) callbacks[i]; diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/com/sun/security/sasl/Provider.java --- a/jdk/src/share/classes/com/sun/security/sasl/Provider.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/com/sun/security/sasl/Provider.java Wed Jul 05 16:59:43 2017 +0200 @@ -51,7 +51,7 @@ " server mechanisms for: DIGEST-MD5, GSSAPI, CRAM-MD5)"; public Provider() { - super("SunSASL", 1.5, info); + super("SunSASL", 1.7d, info); AccessController.doPrivileged(new PrivilegedAction() { public Void run() { diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/lang/EnumConstantNotPresentException.java --- a/jdk/src/share/classes/java/lang/EnumConstantNotPresentException.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/lang/EnumConstantNotPresentException.java Wed Jul 05 16:59:43 2017 +0200 @@ -28,8 +28,12 @@ /** * Thrown when an application tries to access an enum constant by name * and the enum type contains no constant with the specified name. + * This exception can be thrown by the {@linkplain + * java.lang.reflect.AnnotatedElement API used to read annotations + * reflectively}. * * @author Josh Bloch + * @see java.lang.reflect.AnnotatedElement * @since 1.5 */ public class EnumConstantNotPresentException extends RuntimeException { diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/lang/String.java --- a/jdk/src/share/classes/java/lang/String.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/lang/String.java Wed Jul 05 16:59:43 2017 +0200 @@ -2301,6 +2301,54 @@ * @spec JSR-51 */ public String[] split(String regex, int limit) { + /* fastpath if the regex is a + (1)one-char String and this character is not one of the + RegEx's meta characters ".$|()[{^?*+\\", or + (2)two-char String and the first char is the backslash and + the second is not the ascii digit or ascii letter. + */ + char ch = 0; + if (((regex.count == 1 && + ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) || + (regex.length() == 2 && + regex.charAt(0) == '\\' && + (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 && + ((ch-'a')|('z'-ch)) < 0 && + ((ch-'A')|('Z'-ch)) < 0)) && + (ch < Character.MIN_HIGH_SURROGATE || + ch > Character.MAX_LOW_SURROGATE)) + { + int off = 0; + int next = 0; + boolean limited = limit > 0; + ArrayList list = new ArrayList(); + while ((next = indexOf(ch, off)) != -1) { + if (!limited || list.size() < limit - 1) { + list.add(substring(off, next)); + off = next + 1; + } else { // last one + //assert (list.size() == limit - 1); + list.add(substring(off, count)); + off = count; + break; + } + } + // If no match was found, return this + if (off == 0) + return new String[] { this }; + + // Add remaining segment + if (!limited || list.size() < limit) + list.add(substring(off, count)); + + // Construct result + int resultSize = list.size(); + if (limit == 0) + while (resultSize > 0 && list.get(resultSize-1).length() == 0) + resultSize--; + String[] result = new String[resultSize]; + return list.subList(0, resultSize).toArray(result); + } return Pattern.compile(regex).split(this, limit); } diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/lang/TypeNotPresentException.java --- a/jdk/src/share/classes/java/lang/TypeNotPresentException.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/lang/TypeNotPresentException.java Wed Jul 05 16:59:43 2017 +0200 @@ -35,8 +35,12 @@ *

Note that this exception may be used when undefined type variables * are accessed as well as when types (e.g., classes, interfaces or * annotation types) are loaded. + * In particular, this exception can be thrown by the {@linkplain + * java.lang.reflect.AnnotatedElement API used to read annotations + * reflectively}. * * @author Josh Bloch + * @see java.lang.reflect.AnnotatedElement * @since 1.5 */ public class TypeNotPresentException extends RuntimeException { diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/lang/annotation/AnnotationFormatError.java --- a/jdk/src/share/classes/java/lang/annotation/AnnotationFormatError.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/lang/annotation/AnnotationFormatError.java Wed Jul 05 16:59:43 2017 +0200 @@ -28,8 +28,12 @@ /** * Thrown when the annotation parser attempts to read an annotation * from a class file and determines that the annotation is malformed. + * This error can be thrown by the {@linkplain + * java.lang.reflect.AnnotatedElement API used to read annotations + * reflectively}. * * @author Josh Bloch + * @see java.lang.reflect.AnnotatedElement * @since 1.5 */ public class AnnotationFormatError extends Error { diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/lang/annotation/AnnotationTypeMismatchException.java --- a/jdk/src/share/classes/java/lang/annotation/AnnotationTypeMismatchException.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/lang/annotation/AnnotationTypeMismatchException.java Wed Jul 05 16:59:43 2017 +0200 @@ -30,8 +30,12 @@ * Thrown to indicate that a program has attempted to access an element of * an annotation whose type has changed after the annotation was compiled * (or serialized). + * This exception can be thrown by the {@linkplain + * java.lang.reflect.AnnotatedElement API used to read annotations + * reflectively}. * * @author Josh Bloch + * @see java.lang.reflect.AnnotatedElement * @since 1.5 */ public class AnnotationTypeMismatchException extends RuntimeException { diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/lang/annotation/IncompleteAnnotationException.java --- a/jdk/src/share/classes/java/lang/annotation/IncompleteAnnotationException.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/lang/annotation/IncompleteAnnotationException.java Wed Jul 05 16:59:43 2017 +0200 @@ -30,8 +30,12 @@ * an annotation type that was added to the annotation type definition after * the annotation was compiled (or serialized). This exception will not be * thrown if the new element has a default value. + * This exception can be thrown by the {@linkplain + * java.lang.reflect.AnnotatedElement API used to read annotations + * reflectively}. * * @author Josh Bloch + * @see java.lang.reflect.AnnotatedElement * @since 1.5 */ public class IncompleteAnnotationException extends RuntimeException { diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java --- a/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java Wed Jul 05 16:59:43 2017 +0200 @@ -50,6 +50,11 @@ * java.lang.annotation.AnnotationTypeMismatchException} or an * {@link java.lang.annotation.IncompleteAnnotationException}. * + * @see java.lang.EnumConstantNotPresentException + * @see java.lang.TypeNotPresentException + * @see java.lang.annotation.AnnotationFormatError + * @see java.lang.annotation.AnnotationTypeMismatchException + * @see java.lang.annotation.IncompleteAnnotationException * @since 1.5 * @author Josh Bloch */ diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/nio/channels/AsynchronousByteChannel.java --- a/jdk/src/share/classes/java/nio/channels/AsynchronousByteChannel.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousByteChannel.java Wed Jul 05 16:59:43 2017 +0200 @@ -56,18 +56,18 @@ /** * Reads a sequence of bytes from this channel into the given buffer. * - *

This method initiates an operation to read a sequence of bytes from - * this channel into the given buffer. The method returns a {@link Future} - * representing the pending result of the operation. The result of the - * operation, obtained by invoking the {@code Future} 's {@link - * Future#get() get} method, is the number of bytes read or {@code -1} if - * all bytes have been read and the channel has reached end-of-stream. + *

This method initiates an asynchronous read operation to read a + * sequence of bytes from this channel into the given buffer. The {@code + * handler} parameter is a completion handler that is invoked when the read + * operation completes (or fails). The result passed to the completion + * handler is the number of bytes read or {@code -1} if no bytes could be + * read because the channel has reached end-of-stream. * - *

This method initiates a read operation to read up to r bytes - * from the channel, where r is the number of bytes remaining in the - * buffer, that is, {@code dst.remaining()} at the time that the read is - * attempted. Where r is 0, the read operation completes immediately - * with a result of {@code 0} without initiating an I/O operation. + *

The read operation may read up to r bytes from the channel, + * where r is the number of bytes remaining in the buffer, that is, + * {@code dst.remaining()} at the time that the read is attempted. Where + * r is 0, the read operation completes immediately with a result of + * {@code 0} without initiating an I/O operation. * *

Suppose that a byte sequence of length n is read, where * 0 < n <= r. @@ -79,44 +79,46 @@ * p + n; its limit will not have changed. * *

Buffers are not safe for use by multiple concurrent threads so care - * should be taken to not to access the buffer until the operaton has completed. + * should be taken to not access the buffer until the operation has + * completed. * *

This method may be invoked at any time. Some channel types may not * allow more than one read to be outstanding at any given time. If a thread * initiates a read operation before a previous read operation has * completed then a {@link ReadPendingException} will be thrown. * - *

The handler parameter is used to specify a {@link - * CompletionHandler}. When the read operation completes the handler's - * {@link CompletionHandler#completed completed} method is executed. - * - * * @param dst * The buffer into which bytes are to be transferred * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The completion handler object; can be {@code null} - * - * @return A Future representing the result of the operation + * The completion handler * * @throws IllegalArgumentException * If the buffer is read-only * @throws ReadPendingException * If the channel does not allow more than one read to be outstanding * and a previous read has not completed + * @throws ShutdownChannelGroupException + * If the channel is associated with a {@link AsynchronousChannelGroup + * group} that has terminated */ - Future read(ByteBuffer dst, - A attachment, - CompletionHandler handler); + void read(ByteBuffer dst, + A attachment, + CompletionHandler handler); /** * Reads a sequence of bytes from this channel into the given buffer. * - *

An invocation of this method of the form c.read(dst) - * behaves in exactly the same manner as the invocation - *

-     * c.read(dst, null, null);
+ *

This method initiates an asynchronous read operation to read a + * sequence of bytes from this channel into the given buffer. The method + * behaves in exactly the same manner as the {@link + * #read(ByteBuffer,Object,CompletionHandler) + * read(ByteBuffer,Object,CompletionHandler)} method except that instead + * of specifying a completion handler, this method returns a {@code Future} + * representing the pending result. The {@code Future}'s {@link Future#get() + * get} method returns the number of bytes read or {@code -1} if no bytes + * could be read because the channel has reached end-of-stream. * * @param dst * The buffer into which bytes are to be transferred @@ -134,17 +136,17 @@ /** * Writes a sequence of bytes to this channel from the given buffer. * - *

This method initiates an operation to write a sequence of bytes to - * this channel from the given buffer. This method returns a {@link - * Future} representing the pending result of the operation. The result - * of the operation, obtained by invoking the Future's {@link - * Future#get() get} method, is the number of bytes written, possibly zero. + *

This method initiates an asynchronous write operation to write a + * sequence of bytes to this channel from the given buffer. The {@code + * handler} parameter is a completion handler that is invoked when the write + * operation completes (or fails). The result passed to the completion + * handler is the number of bytes written. * - *

This method initiates a write operation to write up to r bytes - * to the channel, where r is the number of bytes remaining in the - * buffer, that is, {@code src.remaining()} at the moment the write is - * attempted. Where r is 0, the write operation completes immediately - * with a result of {@code 0} without initiating an I/O operation. + *

The write operation may write up to r bytes to the channel, + * where r is the number of bytes remaining in the buffer, that is, + * {@code src.remaining()} at the time that the write is attempted. Where + * r is 0, the write operation completes immediately with a result of + * {@code 0} without initiating an I/O operation. * *

Suppose that a byte sequence of length n is written, where * 0 < n <= r. @@ -156,41 +158,43 @@ * p + n; its limit will not have changed. * *

Buffers are not safe for use by multiple concurrent threads so care - * should be taken to not to access the buffer until the operaton has completed. + * should be taken to not access the buffer until the operation has + * completed. * *

This method may be invoked at any time. Some channel types may not * allow more than one write to be outstanding at any given time. If a thread * initiates a write operation before a previous write operation has * completed then a {@link WritePendingException} will be thrown. * - *

The handler parameter is used to specify a {@link - * CompletionHandler}. When the write operation completes the handler's - * {@link CompletionHandler#completed completed} method is executed. - * * @param src * The buffer from which bytes are to be retrieved * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The completion handler object; can be {@code null} - * - * @return A Future representing the result of the operation + * The completion handler object * * @throws WritePendingException * If the channel does not allow more than one write to be outstanding * and a previous write has not completed + * @throws ShutdownChannelGroupException + * If the channel is associated with a {@link AsynchronousChannelGroup + * group} that has terminated */ - Future write(ByteBuffer src, - A attachment, - CompletionHandler handler); + void write(ByteBuffer src, + A attachment, + CompletionHandler handler); /** * Writes a sequence of bytes to this channel from the given buffer. * - *

An invocation of this method of the form c.write(src) - * behaves in exactly the same manner as the invocation - *

-     * c.write(src, null, null);
+ *

This method initiates an asynchronous write operation to write a + * sequence of bytes to this channel from the given buffer. The method + * behaves in exactly the same manner as the {@link + * #write(ByteBuffer,Object,CompletionHandler) + * write(ByteBuffer,Object,CompletionHandler)} method except that instead + * of specifying a completion handler, this method returns a {@code Future} + * representing the pending result. The {@code Future}'s {@link Future#get() + * get} method returns the number of bytes written. * * @param src * The buffer from which bytes are to be retrieved diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/nio/channels/AsynchronousChannel.java --- a/jdk/src/share/classes/java/nio/channels/AsynchronousChannel.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousChannel.java Wed Jul 05 16:59:43 2017 +0200 @@ -34,7 +34,8 @@ * *

    *
  1. {@link Future}<V> operation(...)
  2. - *
  3. Future<V> operation(... A attachment, {@link CompletionHandler}<V,? super A> handler)
  4. + *
  5. void operation(... A attachment, {@link
    + *   CompletionHandler}<V,? super A> handler)
  6. *
* * where operation is the name of the I/O operation (read or write for @@ -48,7 +49,7 @@ * interface may be used to check if the operation has completed, wait for its * completion, and to retrieve the result. In the second form, a {@link * CompletionHandler} is invoked to consume the result of the I/O operation when - * it completes, fails, or is cancelled. + * it completes or fails. * *

A channel that implements this interface is asynchronously * closeable: If an I/O operation is outstanding on the channel and the @@ -63,33 +64,33 @@ *

Cancellation

* *

The {@code Future} interface defines the {@link Future#cancel cancel} - * method to cancel execution of a task. - * - *

Where the {@code cancel} method is invoked with the {@code - * mayInterruptIfRunning} parameter set to {@code true} then the I/O operation - * may be interrupted by closing the channel. This will cause any other I/O - * operations outstanding on the channel to complete with the exception {@link - * AsynchronousCloseException}. + * method to cancel execution. This causes all threads waiting on the result of + * the I/O operation to throw {@link java.util.concurrent.CancellationException}. + * Whether the underlying I/O operation can be cancelled is highly implementation + * specific and therefore not specified. Where cancellation leaves the channel, + * or the entity to which it is connected, in an inconsistent state, then the + * channel is put into an implementation specific error state that + * prevents further attempts to initiate I/O operations that are similar + * to the operation that was cancelled. For example, if a read operation is + * cancelled but the implementation cannot guarantee that bytes have not been + * read from the channel then it puts the channel into an error state; further + * attempts to initiate a {@code read} operation cause an unspecified runtime + * exception to be thrown. Similarly, if a write operation is cancelled but the + * implementation cannot guarantee that bytes have not been written to the + * channel then subsequent attempts to initiate a {@code write} will fail with + * an unspecified runtime exception. * - *

If a {@code CompletionHandler} is specified when initiating an I/O - * operation, and the {@code cancel} method is invoked to cancel the I/O - * operation before it completes, then the {@code CompletionHandler}'s {@link - * CompletionHandler#cancelled cancelled} method is invoked. - * - *

If an implementation of this interface supports a means to cancel I/O - * operations, and where cancellation may leave the channel, or the entity to - * which it is connected, in an inconsistent state, then the channel is put into - * an implementation specific error state that prevents further - * attempts to initiate I/O operations on the channel. For example, if a read - * operation is cancelled but the implementation cannot guarantee that bytes - * have not been read from the channel then it puts the channel into error state - * state; further attempts to initiate a {@code read} operation causes an - * unspecified runtime exception to be thrown. + *

Where the {@link Future#cancel cancel} method is invoked with the {@code + * mayInterruptIfRunning} parameter set to {@code true} then the I/O operation + * may be interrupted by closing the channel. In that case all threads waiting + * on the result of the I/O operation throw {@code CancellationException} and + * any other I/O operations outstanding on the channel complete with the + * exception {@link AsynchronousCloseException}. * *

Where the {@code cancel} method is invoked to cancel read or write - * operations then it recommended that all buffers used in the I/O operations be - * discarded or care taken to ensure that the buffers are not accessed while the - * channel remains open. + * operations then it is recommended that all buffers used in the I/O operations + * be discarded or care taken to ensure that the buffers are not accessed while + * the channel remains open. * * @since 1.7 */ @@ -102,7 +103,7 @@ * *

Any outstanding asynchronous operations upon this channel will * complete with the exception {@link AsynchronousCloseException}. After a - * channel is closed then further attempts to initiate asynchronous I/O + * channel is closed, further attempts to initiate asynchronous I/O * operations complete immediately with cause {@link ClosedChannelException}. * *

This method otherwise behaves exactly as specified by the {@link diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java --- a/jdk/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java Wed Jul 05 16:59:43 2017 +0200 @@ -109,19 +109,13 @@ * // print the source address of all packets that we receive * dc.receive(buffer, buffer, new CompletionHandler<SocketAddress,ByteBuffer>() { * public void completed(SocketAddress sa, ByteBuffer buffer) { - * try { - * System.out.println(sa); - * - * buffer.clear(); - * dc.receive(buffer, buffer, this); - * } catch (...) { ... } + * System.out.println(sa); + * buffer.clear(); + * dc.receive(buffer, buffer, this); * } * public void failed(Throwable exc, ByteBuffer buffer) { * ... * } - * public void cancelled(ByteBuffer buffer) { - * ... - * } * }); * * @@ -314,10 +308,10 @@ /** * Receives a datagram via this channel. * - *

This method initiates the receiving of a datagram, returning a - * {@code Future} representing the pending result of the operation. - * The {@code Future}'s {@link Future#get() get} method returns - * the source address of the datagram upon successful completion. + *

This method initiates the receiving of a datagram into the given + * buffer. The {@code handler} parameter is a completion handler that is + * invoked when the receive operation completes (or fails). The result + * passed to the completion handler is the datagram's source address. * *

The datagram is transferred into the given byte buffer starting at * its current position, as if by a regular {@link AsynchronousByteChannel#read @@ -350,28 +344,26 @@ * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return a {@code Future} object representing the pending result + * The handler for consuming the result * * @throws IllegalArgumentException * If the timeout is negative or the buffer is read-only * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ - public abstract Future receive(ByteBuffer dst, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler); + public abstract void receive(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler); /** * Receives a datagram via this channel. * - *

This method initiates the receiving of a datagram, returning a - * {@code Future} representing the pending result of the operation. - * The {@code Future}'s {@link Future#get() get} method returns - * the source address of the datagram upon successful completion. + *

This method initiates the receiving of a datagram into the given + * buffer. The {@code handler} parameter is a completion handler that is + * invoked when the receive operation completes (or fails). The result + * passed to the completion handler is the datagram's source address. * *

This method is equivalent to invoking {@link * #receive(ByteBuffer,long,TimeUnit,Object,CompletionHandler)} with a @@ -382,34 +374,30 @@ * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return a {@code Future} object representing the pending result + * The handler for consuming the result * * @throws IllegalArgumentException * If the buffer is read-only * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ - public final Future receive(ByteBuffer dst, - A attachment, - CompletionHandler handler) + public final void receive(ByteBuffer dst, + A attachment, + CompletionHandler handler) { - return receive(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler); + receive(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler); } /** * Receives a datagram via this channel. * - *

This method initiates the receiving of a datagram, returning a - * {@code Future} representing the pending result of the operation. - * The {@code Future}'s {@link Future#get() get} method returns - * the source address of the datagram upon successful completion. - * - *

This method is equivalent to invoking {@link - * #receive(ByteBuffer,long,TimeUnit,Object,CompletionHandler)} with a - * timeout of {@code 0L}, and an attachment and completion handler - * of {@code null}. + *

This method initiates the receiving of a datagram into the given + * buffer. The method behaves in exactly the same manner as the {@link + * #receive(ByteBuffer,Object,CompletionHandler) + * receive(ByteBuffer,Object,CompletionHandler)} method except that instead + * of specifying a completion handler, this method returns a {@code Future} + * representing the pending result. The {@code Future}'s {@link Future#get() + * get} method returns the datagram's source address. * * @param dst * The buffer into which the datagram is to be transferred @@ -419,84 +407,19 @@ * @throws IllegalArgumentException * If the buffer is read-only */ - public final Future receive(ByteBuffer dst) { - return receive(dst, 0L, TimeUnit.MILLISECONDS, null, null); - } + public abstract Future receive(ByteBuffer dst); /** * Sends a datagram via this channel. * - *

This method initiates sending of a datagram, returning a - * {@code Future} representing the pending result of the operation. - * The operation sends the remaining bytes in the given buffer as a single - * datagram to the given target address. The result of the operation, obtained - * by invoking the {@code Future}'s {@link Future#get() get} - * method, is the number of bytes sent. - * - *

The datagram is transferred from the byte buffer as if by a regular - * {@link AsynchronousByteChannel#write write} operation. - * - *

If a timeout is specified and the timeout elapses before the operation - * completes then the operation completes with the exception {@link - * InterruptedByTimeoutException}. When a timeout elapses then the state of - * the {@link ByteBuffer} is not defined. The buffers should be discarded or - * at least care must be taken to ensure that the buffer is not accessed - * while the channel remains open. - * - *

If there is a security manager installed and the channel is not - * connected then this method verifies that the target address and port number - * are permitted by the security manager's {@link SecurityManager#checkConnect - * checkConnect} method. The overhead of this security check can be avoided - * by first connecting the socket via the {@link #connect connect} method. - * - * @param src - * The buffer containing the datagram to be sent - * @param target - * The address to which the datagram is to be sent - * @param timeout - * The timeout, or {@code 0L} for no timeout - * @param unit - * The time unit of the {@code timeout} argument - * @param attachment - * The object to attach to the I/O operation; can be {@code null} - * @param handler - * The handler for consuming the result; can be {@code null} + *

This method initiates sending of a datagram from the given buffer to + * the given address. The {@code handler} parameter is a completion handler + * that is invoked when the send completes (or fails). The result passed to + * the completion handler is the number of bytes sent. * - * @return a {@code Future} object representing the pending result - * - * @throws UnresolvedAddressException - * If the given remote address is not fully resolved - * @throws UnsupportedAddressTypeException - * If the type of the given remote address is not supported - * @throws IllegalArgumentException - * If the timeout is negative, or if the channel's socket is - * connected to an address that is not equal to {@code target} - * @throws SecurityException - * If a security manager has been installed and it does not permit - * datagrams to be sent to the given address - * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown - */ - public abstract Future send(ByteBuffer src, - SocketAddress target, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler); - - /** - * Sends a datagram via this channel. - * - *

This method initiates sending of a datagram, returning a - * {@code Future} representing the pending result of the operation. - * The operation sends the remaining bytes in the given buffer as a single - * datagram to the given target address. The result of the operation, obtained - * by invoking the {@code Future}'s {@link Future#get() get} - * method, is the number of bytes sent. - * - *

This method is equivalent to invoking {@link - * #send(ByteBuffer,SocketAddress,long,TimeUnit,Object,CompletionHandler)} - * with a timeout of {@code 0L}. + *

Otherwise this method works in the same manner as the {@link + * AsynchronousByteChannel#write(ByteBuffer,Object,CompletionHandler)} + * method. * * @param src * The buffer containing the datagram to be sent @@ -505,9 +428,7 @@ * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return a {@code Future} object representing the pending result + * The handler for consuming the result * * @throws UnresolvedAddressException * If the given remote address is not fully resolved @@ -520,30 +441,23 @@ * If a security manager has been installed and it does not permit * datagrams to be sent to the given address * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ - public final Future send(ByteBuffer src, - SocketAddress target, - A attachment, - CompletionHandler handler) - { - return send(src, target, 0L, TimeUnit.MILLISECONDS, attachment, handler); - } + public abstract void send(ByteBuffer src, + SocketAddress target, + A attachment, + CompletionHandler handler); /** * Sends a datagram via this channel. * - *

This method initiates sending of a datagram, returning a - * {@code Future} representing the pending result of the operation. - * The operation sends the remaining bytes in the given buffer as a single - * datagram to the given target address. The result of the operation, obtained - * by invoking the {@code Future}'s {@link Future#get() get} - * method, is the number of bytes sent. - * - *

This method is equivalent to invoking {@link - * #send(ByteBuffer,SocketAddress,long,TimeUnit,Object,CompletionHandler)} - * with a timeout of {@code 0L} and an attachment and completion handler - * of {@code null}. + *

This method initiates sending of a datagram from the given buffer to + * the given address. The method behaves in exactly the same manner as the + * {@link #send(ByteBuffer,SocketAddress,Object,CompletionHandler) + * send(ByteBuffer,SocketAddress,Object,CompletionHandler)} method except + * that instead of specifying a completion handler, this method returns a + * {@code Future} representing the pending result. The {@code Future}'s + * {@link Future#get() get} method returns the number of bytes sent. * * @param src * The buffer containing the datagram to be sent @@ -563,17 +477,15 @@ * If a security manager has been installed and it does not permit * datagrams to be sent to the given address */ - public final Future send(ByteBuffer src, SocketAddress target) { - return send(src, target, 0L, TimeUnit.MILLISECONDS, null, null); - } + public abstract Future send(ByteBuffer src, SocketAddress target); /** * Receives a datagram via this channel. * - *

This method initiates the receiving of a datagram, returning a - * {@code Future} representing the pending result of the operation. - * The {@code Future}'s {@link Future#get() get} method returns - * the number of bytes transferred upon successful completion. + *

This method initiates the receiving of a datagram into the given + * buffer. The {@code handler} parameter is a completion handler that is + * invoked when the receive operation completes (or fails). The result + * passed to the completion handler is number of bytes read. * *

This method may only be invoked if this channel is connected, and it * only accepts datagrams from the peer that the channel is connected too. @@ -599,120 +511,62 @@ * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return a {@code Future} object representing the pending result + * The handler for consuming the result * * @throws IllegalArgumentException * If the timeout is negative or buffer is read-only * @throws NotYetConnectedException * If this channel is not connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ - public abstract Future read(ByteBuffer dst, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler); + public abstract void read(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler); /** * @throws NotYetConnectedException * If this channel is not connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ @Override - public final Future read(ByteBuffer dst, - A attachment, - CompletionHandler handler) + public final void read(ByteBuffer dst, + A attachment, + CompletionHandler handler) { - return read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler); + read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler); } /** * @throws NotYetConnectedException * If this channel is not connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ @Override - public final Future read(ByteBuffer dst) { - return read(dst, 0L, TimeUnit.MILLISECONDS, null, null); - } - - /** - * Writes a datagram to this channel. - * - *

This method initiates sending of a datagram, returning a - * {@code Future} representing the pending result of the operation. - * The operation sends the remaining bytes in the given buffer as a single - * datagram. The result of the operation, obtained by invoking the - * {@code Future}'s {@link Future#get() get} method, is the - * number of bytes sent. - * - *

The datagram is transferred from the byte buffer as if by a regular - * {@link AsynchronousByteChannel#write write} operation. - * - *

This method may only be invoked if this channel is connected, - * in which case it sends datagrams directly to the socket's peer. Otherwise - * it behaves exactly as specified in the {@link - * AsynchronousByteChannel} interface. - * - *

If a timeout is specified and the timeout elapses before the operation - * completes then the operation completes with the exception {@link - * InterruptedByTimeoutException}. When a timeout elapses then the state of - * the {@link ByteBuffer} is not defined. The buffers should be discarded or - * at least care must be taken to ensure that the buffer is not accessed - * while the channel remains open. - * - * @param src - * The buffer containing the datagram to be sent - * @param timeout - * The timeout, or {@code 0L} for no timeout - * @param unit - * The time unit of the {@code timeout} argument - * @param attachment - * The object to attach to the I/O operation; can be {@code null} - * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return a {@code Future} object representing the pending result - * - * @throws IllegalArgumentException - * If the timeout is negative - * @throws NotYetConnectedException - * If this channel is not connected - * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown - */ - public abstract Future write(ByteBuffer src, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler); - /** - * @throws NotYetConnectedException - * If this channel is not connected - * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown - */ - @Override - public final Future write(ByteBuffer src, - A attachment, - CompletionHandler handler) - { - return write(src, 0L, TimeUnit.MILLISECONDS, attachment, handler); - } + public abstract Future read(ByteBuffer dst); /** * @throws NotYetConnectedException * If this channel is not connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ @Override - public final Future write(ByteBuffer src) { - return write(src, 0L, TimeUnit.MILLISECONDS, null, null); - } + public abstract void write(ByteBuffer src, + A attachment, + CompletionHandler handler); + + + /** + * @throws NotYetConnectedException + * If this channel is not connected + * @throws ShutdownChannelGroupException + * If the channel group has terminated + */ + @Override + public abstract Future write(ByteBuffer src); } diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/nio/channels/AsynchronousFileChannel.java --- a/jdk/src/share/classes/java/nio/channels/AsynchronousFileChannel.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousFileChannel.java Wed Jul 05 16:59:43 2017 +0200 @@ -48,7 +48,12 @@ * *

An asynchronous file channel does not have a current position * within the file. Instead, the file position is specified to each read and - * write operation. + * write methd that initiate asynchronous operations. A {@link CompletionHandler} + * is specified as a parameter and is invoked to consume the result of the I/O + * operation. This class also defines read and write methods that initiate + * asynchronous operations, returning a {@link Future} to represent the pending + * result of the operation. The {@code Future} may be used to check if the + * operation has completed, to wait for its completion. * *

In addition to read and write operations, this class defines the * following operations:

@@ -59,18 +64,11 @@ * out} to the underlying storage device, ensuring that data are not * lost in the event of a system crash.

* - *
  • A region of a file may be {@link FileLock locked} - * against access by other programs.

  • + *
  • A region of a file may be {@link #lock locked} against + * access by other programs.

  • * * * - *

    The {@link #read read}, {@link #write write}, and {@link #lock lock} - * methods defined by this class are asynchronous and return a {@link Future} - * to represent the pending result of the operation. This may be used to check - * if the operation has completed, to wait for its completion, and to retrieve - * the result. These method may optionally specify a {@link CompletionHandler} - * that is invoked to consume the result of the I/O operation when it completes. - * *

    An {@code AsynchronousFileChannel} is associated with a thread pool to * which tasks are submitted to handle I/O events and dispatch to completion * handlers that consume the results of I/O operations on the channel. The @@ -123,22 +121,6 @@ } /** - * Closes this channel. - * - *

    If this channel is associated with its own thread pool then closing - * the channel causes the thread pool to shutdown after all actively - * executing completion handlers have completed. No attempt is made to stop - * or interrupt actively completion handlers. - * - *

    This method otherwise behaves exactly as specified by the {@link - * AsynchronousChannel} interface. - * - * @throws IOException {@inheritDoc} - */ - @Override - public abstract void close() throws IOException; - - /** * Opens or creates a file for reading and/or writing, returning an * asynchronous file channel to access the file. * @@ -215,9 +197,8 @@ * should be taken when configuring the {@code Executor}. Minimally it * should support an unbounded work queue and should not run tasks on the * caller thread of the {@link ExecutorService#execute execute} method. - * {@link #close Closing} the channel results in the orderly {@link - * ExecutorService#shutdown shutdown} of the executor service. Shutting down - * the executor service by other means results in unspecified behavior. + * Shutting down the executor service while the channel is open results in + * unspecified behavior. * *

    The {@code attrs} parameter is an optional array of file {@link * FileAttribute file-attributes} to set atomically when creating the file. @@ -276,7 +257,8 @@ *

    An invocation of this method behaves in exactly the same way as the * invocation *

    -     *     ch.{@link #open(Path,Set,ExecutorService,FileAttribute[]) open}(file, opts, null, new FileAttribute<?>[0]);
    +     *     ch.{@link #open(Path,Set,ExecutorService,FileAttribute[])
    +     *       open}(file, opts, null, new FileAttribute<?>[0]);
          * 
    * where {@code opts} is a {@code Set} containing the options specified to * this method. @@ -405,10 +387,11 @@ /** * Acquires a lock on the given region of this channel's file. * - *

    This method initiates an operation to acquire a lock on the given region - * of this channel's file. The method returns a {@code Future} representing - * the pending result of the operation. Its {@link Future#get() get} - * method returns the {@link FileLock} on successful completion. + *

    This method initiates an operation to acquire a lock on the given + * region of this channel's file. The {@code handler} parameter is a + * completion handler that is invoked when the lock is acquired (or the + * operation fails). The result passed to the completion handler is the + * resulting {@code FileLock}. * *

    The region specified by the {@code position} and {@code size} * parameters need not be contained within, or even overlap, the actual @@ -455,9 +438,7 @@ * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return a {@code Future} object representing the pending result + * The handler for consuming the result * * @throws OverlappingFileLockException * If a lock that overlaps the requested region is already held by @@ -466,26 +447,24 @@ * @throws IllegalArgumentException * If the preconditions on the parameters do not hold * @throws NonReadableChannelException - * If {@code shared} is true this channel but was not opened for reading + * If {@code shared} is true but this channel was not opened for reading * @throws NonWritableChannelException * If {@code shared} is false but this channel was not opened for writing - * @throws ShutdownChannelGroupException - * If a handler is specified, the channel is closed, and the channel - * was originally created with its own thread pool */ - public abstract Future lock(long position, - long size, - boolean shared, - A attachment, - CompletionHandler handler); + public abstract void lock(long position, + long size, + boolean shared, + A attachment, + CompletionHandler handler); /** * Acquires an exclusive lock on this channel's file. * - *

    This method initiates an operation to acquire an exclusive lock on this - * channel's file. The method returns a {@code Future} representing - * the pending result of the operation. Its {@link Future#get() get} - * method returns the {@link FileLock} on successful completion. + *

    This method initiates an operation to acquire a lock on the given + * region of this channel's file. The {@code handler} parameter is a + * completion handler that is invoked when the lock is acquired (or the + * operation fails). The result passed to the completion handler is the + * resulting {@code FileLock}. * *

    An invocation of this method of the form {@code ch.lock(att,handler)} * behaves in exactly the same way as the invocation @@ -496,7 +475,70 @@ * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} + * The handler for consuming the result + * + * @throws OverlappingFileLockException + * If a lock is already held by this Java virtual machine, or there + * is already a pending attempt to lock a region + * @throws NonWritableChannelException + * If this channel was not opened for writing + */ + public final void lock(A attachment, + CompletionHandler handler) + { + lock(0L, Long.MAX_VALUE, false, attachment, handler); + } + + /** + * Acquires a lock on the given region of this channel's file. + * + *

    This method initiates an operation to acquire a lock on the given + * region of this channel's file. The method behaves in exactly the same + * manner as the {@link #lock(long, long, boolean, Object, CompletionHandler)} + * method except that instead of specifying a completion handler, this + * method returns a {@code Future} representing the pending result. The + * {@code Future}'s {@link Future#get() get} method returns the {@link + * FileLock} on successful completion. + * + * @param position + * The position at which the locked region is to start; must be + * non-negative + * @param size + * The size of the locked region; must be non-negative, and the sum + * {@code position} + {@code size} must be non-negative + * @param shared + * {@code true} to request a shared lock, in which case this + * channel must be open for reading (and possibly writing); + * {@code false} to request an exclusive lock, in which case this + * channel must be open for writing (and possibly reading) + * + * @return a {@code Future} object representing the pending result + * + * @throws OverlappingFileLockException + * If a lock is already held by this Java virtual machine, or there + * is already a pending attempt to lock a region + * @throws IllegalArgumentException + * If the preconditions on the parameters do not hold + * @throws NonReadableChannelException + * If {@code shared} is true but this channel was not opened for reading + * @throws NonWritableChannelException + * If {@code shared} is false but this channel was not opened for writing + */ + public abstract Future lock(long position, long size, boolean shared); + + /** + * Acquires an exclusive lock on this channel's file. + * + *

    This method initiates an operation to acquire an exclusive lock on this + * channel's file. The method returns a {@code Future} representing the + * pending result of the operation. The {@code Future}'s {@link Future#get() + * get} method returns the {@link FileLock} on successful completion. + * + *

    An invocation of this method behaves in exactly the same way as the + * invocation + *

    +     *     ch.{@link #lock(long,long,boolean) lock}(0L, Long.MAX_VALUE, false)
    +     * 
    * * @return a {@code Future} object representing the pending result * @@ -505,40 +547,9 @@ * is already a pending attempt to lock a region * @throws NonWritableChannelException * If this channel was not opened for writing - * @throws ShutdownChannelGroupException - * If a handler is specified, the channel is closed, and the channel - * was originally created with its own thread pool - */ - public final Future lock(A attachment, - CompletionHandler handler) - { - return lock(0L, Long.MAX_VALUE, false, attachment, handler); - } - - /** - * Acquires an exclusive lock on this channel's file. - * - *

    This method initiates an operation to acquire an exclusive lock on this - * channel's file. The method returns a {@code Future} representing the - * pending result of the operation. Its {@link Future#get() get} method - * returns the {@link FileLock} on successful completion. - * - *

    An invocation of this method behaves in exactly the same way as the - * invocation - *

    -     *     ch.{@link #lock(long,long,boolean,Object,CompletionHandler) lock}(0L, Long.MAX_VALUE, false, null, null)
    -     * 
    - * - * @return A {@code Future} object representing the pending result - * - * @throws OverlappingFileLockException - * If a lock is already held by this Java virtual machine, or there - * is already a pending attempt to lock a region - * @throws NonWritableChannelException - * If this channel was not opened for writing */ public final Future lock() { - return lock(0L, Long.MAX_VALUE, false, null, null); + return lock(0L, Long.MAX_VALUE, false); } /** @@ -576,7 +587,7 @@ * blocked in this method and is attempting to lock an overlapping * region of the same file * @throws NonReadableChannelException - * If {@code shared} is true this channel but was not opened for reading + * If {@code shared} is true but this channel was not opened for reading * @throws NonWritableChannelException * If {@code shared} is false but this channel was not opened for writing * @@ -629,11 +640,10 @@ * starting at the given file position. * *

    This method initiates the reading of a sequence of bytes from this - * channel into the given buffer, starting at the given file position. This - * method returns a {@code Future} representing the pending result of the - * operation. The Future's {@link Future#get() get} method returns the - * number of bytes read or {@code -1} if the given position is greater than - * or equal to the file's size at the time that the read is attempted. + * channel into the given buffer, starting at the given file position. The + * result of the read is the number of bytes read or {@code -1} if the given + * position is greater than or equal to the file's size at the time that the + * read is attempted. * *

    This method works in the same manner as the {@link * AsynchronousByteChannel#read(ByteBuffer,Object,CompletionHandler)} @@ -649,22 +659,17 @@ * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return A {@code Future} object representing the pending result + * The handler for consuming the result * * @throws IllegalArgumentException * If the position is negative or the buffer is read-only * @throws NonReadableChannelException * If this channel was not opened for reading - * @throws ShutdownChannelGroupException - * If a handler is specified, the channel is closed, and the channel - * was originally created with its own thread pool */ - public abstract Future read(ByteBuffer dst, - long position, - A attachment, - CompletionHandler handler); + public abstract void read(ByteBuffer dst, + long position, + A attachment, + CompletionHandler handler); /** * Reads a sequence of bytes from this channel into the given buffer, @@ -673,13 +678,15 @@ *

    This method initiates the reading of a sequence of bytes from this * channel into the given buffer, starting at the given file position. This * method returns a {@code Future} representing the pending result of the - * operation. The Future's {@link Future#get() get} method returns the - * number of bytes read or {@code -1} if the given position is greater + * operation. The {@code Future}'s {@link Future#get() get} method returns + * the number of bytes read or {@code -1} if the given position is greater * than or equal to the file's size at the time that the read is attempted. * - *

    This method is equivalent to invoking {@link - * #read(ByteBuffer,long,Object,CompletionHandler)} with the {@code attachment} - * and handler parameters set to {@code null}. + *

    This method works in the same manner as the {@link + * AsynchronousByteChannel#read(ByteBuffer)} method, except that bytes are + * read starting at the given file position. If the given file position is + * greater than the file's size at the time that the read is attempted then + * no bytes are read. * * @param dst * The buffer into which bytes are to be transferred @@ -694,20 +701,12 @@ * @throws NonReadableChannelException * If this channel was not opened for reading */ - public final Future read(ByteBuffer dst, long position) { - return read(dst, position, null, null); - } + public abstract Future read(ByteBuffer dst, long position); /** * Writes a sequence of bytes to this channel from the given buffer, starting * at the given file position. * - *

    This method initiates the writing of a sequence of bytes to this channel - * from the given buffer, starting at the given file position. The method - * returns a {@code Future} representing the pending result of the write - * operation. The Future's {@link Future#get() get} method returns the - * number of bytes written. - * *

    This method works in the same manner as the {@link * AsynchronousByteChannel#write(ByteBuffer,Object,CompletionHandler)} * method, except that bytes are written starting at the given file position. @@ -724,36 +723,35 @@ * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return A {@code Future} object representing the pending result + * The handler for consuming the result * * @throws IllegalArgumentException * If the position is negative * @throws NonWritableChannelException * If this channel was not opened for writing - * @throws ShutdownChannelGroupException - * If a handler is specified, the channel is closed, and the channel - * was originally created with its own thread pool */ - public abstract Future write(ByteBuffer src, - long position, - A attachment, - CompletionHandler handler); + public abstract void write(ByteBuffer src, + long position, + A attachment, + CompletionHandler handler); /** * Writes a sequence of bytes to this channel from the given buffer, starting * at the given file position. * - *

    This method initiates the writing of a sequence of bytes to this channel - * from the given buffer, starting at the given file position. The method - * returns a {@code Future} representing the pending result of the write - * operation. The Future's {@link Future#get() get} method returns the - * number of bytes written. + *

    This method initiates the writing of a sequence of bytes to this + * channel from the given buffer, starting at the given file position. The + * method returns a {@code Future} representing the pending result of the + * write operation. The {@code Future}'s {@link Future#get() get} method + * returns the number of bytes written. * - *

    This method is equivalent to invoking {@link - * #write(ByteBuffer,long,Object,CompletionHandler)} with the {@code attachment} - * and handler parameters set to {@code null}. + *

    This method works in the same manner as the {@link + * AsynchronousByteChannel#write(ByteBuffer)} method, except that bytes are + * written starting at the given file position. If the given position is + * greater than the file's size, at the time that the write is attempted, + * then the file will be grown to accommodate the new bytes; the values of + * any bytes between the previous end-of-file and the newly-written bytes + * are unspecified. * * @param src * The buffer from which bytes are to be transferred @@ -768,7 +766,5 @@ * @throws NonWritableChannelException * If this channel was not opened for writing */ - public final Future write(ByteBuffer src, long position) { - return write(src, position, null, null); - } + public abstract Future write(ByteBuffer src, long position); } diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java --- a/jdk/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java Wed Jul 05 16:59:43 2017 +0200 @@ -85,9 +85,6 @@ * public void failed(Throwable exc, Void att) { * ... * } - * public void cancelled(Void att) { - * ... - * } * }); * * @@ -240,11 +237,11 @@ /** * Accepts a connection. * - *

    This method initiates accepting a connection made to this channel's - * socket, returning a {@link Future} representing the pending result - * of the operation. The {@code Future}'s {@link Future#get() get} - * method will return the {@link AsynchronousSocketChannel} for the new - * connection on successful completion. + *

    This method initiates an asynchronous operation to accept a + * connection made to this channel's socket. The {@code handler} parameter is + * a completion handler that is invoked when a connection is accepted (or + * the operation fails). The result passed to the completion handler is + * the {@link AsynchronousSocketChannel} to the new connection. * *

    When a new connection is accepted then the resulting {@code * AsynchronousSocketChannel} will be bound to the same {@link @@ -269,35 +266,35 @@ * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return an Future object representing the pending result + * The handler for consuming the result * * @throws AcceptPendingException * If an accept operation is already in progress on this channel * @throws NotYetBoundException * If this channel's socket has not yet been bound * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ - public abstract Future - accept(A attachment, CompletionHandler handler); + public abstract void accept(A attachment, + CompletionHandler handler); /** * Accepts a connection. * - *

    This method is equivalent to invoking {@link - * #accept(Object,CompletionHandler)} with the {@code attachment} - * and {@code handler} parameters set to {@code null}. + *

    This method initiates an asynchronous operation to accept a + * connection made to this channel's socket. The method behaves in exactly + * the same manner as the {@link #accept(Object, CompletionHandler)} method + * except that instead of specifying a completion handler, this method + * returns a {@code Future} representing the pending result. The {@code + * Future}'s {@link Future#get() get} method returns the {@link + * AsynchronousSocketChannel} to the new connection on successful completion. * - * @return an Future object representing the pending result + * @return a {@code Future} object representing the pending result * * @throws AcceptPendingException * If an accept operation is already in progress on this channel * @throws NotYetBoundException * If this channel's socket has not yet been bound */ - public final Future accept() { - return accept(null, null); - } + public abstract Future accept(); } diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java --- a/jdk/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java Wed Jul 05 16:59:43 2017 +0200 @@ -274,14 +274,11 @@ /** * Connects this channel. * - *

    This method initiates an operation to connect this channel, returning - * a {@code Future} representing the pending result of the operation. If - * the connection is successfully established then the {@code Future}'s - * {@link Future#get() get} method will return {@code null}. If the - * connection cannot be established then the channel is closed. In that case, - * invoking the {@code get} method throws {@link - * java.util.concurrent.ExecutionException} with an {@code IOException} as - * the cause. + *

    This method initiates an operation to connect this channel. The + * {@code handler} parameter is a completion handler that is invoked when + * the connection is successfully established or connection cannot be + * established. If the connection cannot be established then the channel is + * closed. * *

    This method performs exactly the same security checks as the {@link * java.net.Socket} class. That is, if a security manager has been @@ -294,9 +291,7 @@ * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return A {@code Future} object representing the pending result + * The handler for consuming the result * * @throws UnresolvedAddressException * If the given remote address is not fully resolved @@ -307,23 +302,26 @@ * @throws ConnectionPendingException * If a connection operation is already in progress on this channel * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated * @throws SecurityException * If a security manager has been installed * and it does not permit access to the given remote endpoint * * @see #getRemoteAddress */ - public abstract Future connect(SocketAddress remote, - A attachment, - CompletionHandler handler); + public abstract void connect(SocketAddress remote, + A attachment, + CompletionHandler handler); /** * Connects this channel. * - *

    This method is equivalent to invoking {@link - * #connect(SocketAddress,Object,CompletionHandler)} with the {@code attachment} - * and handler parameters set to {@code null}. + *

    This method initiates an operation to connect this channel. This + * method behaves in exactly the same manner as the {@link + * #connect(SocketAddress, Object, CompletionHandler)} method except that + * instead of specifying a completion handler, this method returns a {@code + * Future} representing the pending result. The {@code Future}'s {@link + * Future#get() get} method returns {@code null} on successful completion. * * @param remote * The remote address to which this channel is to be connected @@ -342,18 +340,17 @@ * If a security manager has been installed * and it does not permit access to the given remote endpoint */ - public final Future connect(SocketAddress remote) { - return connect(remote, null, null); - } + public abstract Future connect(SocketAddress remote); /** * Reads a sequence of bytes from this channel into the given buffer. * - *

    This method initiates the reading of a sequence of bytes from this - * channel into the given buffer, returning a {@code Future} representing - * the pending result of the operation. The {@code Future}'s {@link - * Future#get() get} method returns the number of bytes read or {@code -1} - * if all bytes have been read and channel has reached end-of-stream. + *

    This method initiates an asynchronous read operation to read a + * sequence of bytes from this channel into the given buffer. The {@code + * handler} parameter is a completion handler that is invoked when the read + * operation completes (or fails). The result passed to the completion + * handler is the number of bytes read or {@code -1} if no bytes could be + * read because the channel has reached end-of-stream. * *

    If a timeout is specified and the timeout elapses before the operation * completes then the operation completes with the exception {@link @@ -376,9 +373,7 @@ * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return A {@code Future} object representing the pending result + * The handler for consuming the result * * @throws IllegalArgumentException * If the {@code timeout} parameter is negative or the buffer is @@ -388,13 +383,13 @@ * @throws NotYetConnectedException * If this channel is not yet connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ - public abstract Future read(ByteBuffer dst, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler); + public abstract void read(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler); /** * @throws IllegalArgumentException {@inheritDoc} @@ -402,14 +397,14 @@ * @throws NotYetConnectedException * If this channel is not yet connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ @Override - public final Future read(ByteBuffer dst, - A attachment, - CompletionHandler handler) + public final void read(ByteBuffer dst, + A attachment, + CompletionHandler handler) { - return read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler); + read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler); } /** @@ -419,16 +414,18 @@ * If this channel is not yet connected */ @Override - public final Future read(ByteBuffer dst) { - return read(dst, 0L, TimeUnit.MILLISECONDS, null, null); - } + public abstract Future read(ByteBuffer dst); /** * Reads a sequence of bytes from this channel into a subsequence of the * given buffers. This operation, sometimes called a scattering read, * is often useful when implementing network protocols that group data into * segments consisting of one or more fixed-length headers followed by a - * variable-length body. + * variable-length body. The {@code handler} parameter is a completion + * handler that is invoked when the read operation completes (or fails). The + * result passed to the completion handler is the number of bytes read or + * {@code -1} if no bytes could be read because the channel has reached + * end-of-stream. * *

    This method initiates a read of up to r bytes from this channel, * where r is the total number of bytes remaining in the specified @@ -456,11 +453,6 @@ * I/O operation is performed with the maximum number of buffers allowed by * the operating system. * - *

    The return value from this method is a {@code Future} representing - * the pending result of the operation. The {@code Future}'s {@link - * Future#get() get} method returns the number of bytes read or {@code -1L} - * if all bytes have been read and the channel has reached end-of-stream. - * *

    If a timeout is specified and the timeout elapses before the operation * completes then it completes with the exception {@link * InterruptedByTimeoutException}. Where a timeout occurs, and the @@ -485,9 +477,7 @@ * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return A {@code Future} object representing the pending result + * The handler for consuming the result * * @throws IndexOutOfBoundsException * If the pre-conditions for the {@code offset} and {@code length} @@ -500,23 +490,24 @@ * @throws NotYetConnectedException * If this channel is not yet connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ - public abstract Future read(ByteBuffer[] dsts, - int offset, - int length, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler); + public abstract void read(ByteBuffer[] dsts, + int offset, + int length, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler); /** * Writes a sequence of bytes to this channel from the given buffer. * - *

    This method initiates the writing of a sequence of bytes to this channel - * from the given buffer, returning a {@code Future} representing the - * pending result of the operation. The {@code Future}'s {@link Future#get() - * get} method will return the number of bytes written. + *

    This method initiates an asynchronous write operation to write a + * sequence of bytes to this channel from the given buffer. The {@code + * handler} parameter is a completion handler that is invoked when the write + * operation completes (or fails). The result passed to the completion + * handler is the number of bytes written. * *

    If a timeout is specified and the timeout elapses before the operation * completes then it completes with the exception {@link @@ -539,9 +530,7 @@ * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return A {@code Future} object representing the pending result + * The handler for consuming the result * * @throws IllegalArgumentException * If the {@code timeout} parameter is negative @@ -550,28 +539,28 @@ * @throws NotYetConnectedException * If this channel is not yet connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ - public abstract Future write(ByteBuffer src, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler); + public abstract void write(ByteBuffer src, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler); /** * @throws WritePendingException {@inheritDoc} * @throws NotYetConnectedException * If this channel is not yet connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ @Override - public final Future write(ByteBuffer src, - A attachment, - CompletionHandler handler) + public final void write(ByteBuffer src, + A attachment, + CompletionHandler handler) { - return write(src, 0L, TimeUnit.MILLISECONDS, attachment, handler); + write(src, 0L, TimeUnit.MILLISECONDS, attachment, handler); } /** @@ -580,16 +569,16 @@ * If this channel is not yet connected */ @Override - public final Future write(ByteBuffer src) { - return write(src, 0L, TimeUnit.MILLISECONDS, null, null); - } + public abstract Future write(ByteBuffer src); /** * Writes a sequence of bytes to this channel from a subsequence of the given * buffers. This operation, sometimes called a gathering write, is * often useful when implementing network protocols that group data into * segments consisting of one or more fixed-length headers followed by a - * variable-length body. + * variable-length body. The {@code handler} parameter is a completion + * handler that is invoked when the write operation completes (or fails). + * The result passed to the completion handler is the number of bytes written. * *

    This method initiates a write of up to r bytes to this channel, * where r is the total number of bytes remaining in the specified @@ -616,10 +605,6 @@ * remaining), exceeds this limit, then the I/O operation is performed with * the maximum number of buffers allowed by the operating system. * - *

    The return value from this method is a {@code Future} representing - * the pending result of the operation. The {@code Future}'s {@link - * Future#get() get} method will return the number of bytes written. - * *

    If a timeout is specified and the timeout elapses before the operation * completes then it completes with the exception {@link * InterruptedByTimeoutException}. Where a timeout occurs, and the @@ -644,9 +629,7 @@ * @param attachment * The object to attach to the I/O operation; can be {@code null} * @param handler - * The handler for consuming the result; can be {@code null} - * - * @return A {@code Future} object representing the pending result + * The handler for consuming the result * * @throws IndexOutOfBoundsException * If the pre-conditions for the {@code offset} and {@code length} @@ -658,13 +641,13 @@ * @throws NotYetConnectedException * If this channel is not yet connected * @throws ShutdownChannelGroupException - * If a handler is specified, and the channel group is shutdown + * If the channel group has terminated */ - public abstract Future write(ByteBuffer[] srcs, - int offset, - int length, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler); + public abstract void write(ByteBuffer[] srcs, + int offset, + int length, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler); } diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/nio/channels/Channels.java --- a/jdk/src/share/classes/java/nio/channels/Channels.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/nio/channels/Channels.java Wed Jul 05 16:59:43 2017 +0200 @@ -182,7 +182,6 @@ } /** - * {@note new} * Constructs a stream that reads bytes from the given channel. * *

    The stream will not be buffered, and it will not support the {@link @@ -258,7 +257,6 @@ } /** - * {@note new} * Constructs a stream that writes bytes to the given channel. * *

    The stream will not be buffered. The stream will be safe for access diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/nio/channels/CompletionHandler.java --- a/jdk/src/share/classes/java/nio/channels/CompletionHandler.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/nio/channels/CompletionHandler.java Wed Jul 05 16:59:43 2017 +0200 @@ -32,11 +32,9 @@ * handler to be specified to consume the result of an asynchronous operation. * The {@link #completed completed} method is invoked when the I/O operation * completes successfully. The {@link #failed failed} method is invoked if the - * I/O operations fails. The {@link #cancelled cancelled} method is invoked when - * the I/O operation is cancelled by invoking the {@link - * java.util.concurrent.Future#cancel cancel} method. The implementations of - * these methods should complete in a timely manner so as to avoid keeping the - * invoking thread from dispatching to other completion handlers. + * I/O operations fails. The implementations of these methods should complete + * in a timely manner so as to avoid keeping the invoking thread from dispatching + * to other completion handlers. * * @param The result type of the I/O operation * @param The type of the object attached to the I/O operation @@ -65,13 +63,4 @@ * The object attached to the I/O operation when it was initiated. */ void failed(Throwable exc, A attachment); - - /** - * Invoked when an operation is cancelled by invoking the {@link - * java.util.concurrent.Future#cancel cancel} method. - * - * @param attachment - * The object attached to the I/O operation when it was initiated. - */ - void cancelled(A attachment); } diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/nio/channels/FileChannel.java --- a/jdk/src/share/classes/java/nio/channels/FileChannel.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/nio/channels/FileChannel.java Wed Jul 05 16:59:43 2017 +0200 @@ -39,8 +39,7 @@ /** * A channel for reading, writing, mapping, and manipulating a file. * - *

    {@note revised} - * A file channel is a {@link SeekableByteChannel} that is connected to + *

    A file channel is a {@link SeekableByteChannel} that is connected to * a file. It has a current position within its file which can * be both {@link #position() queried} and {@link #position(long) * modified}. The file itself contains a variable-length sequence @@ -151,7 +150,6 @@ * @author Mike McCloskey * @author JSR-51 Expert Group * @since 1.4 - * @updated 1.7 */ public abstract class FileChannel @@ -164,7 +162,6 @@ protected FileChannel() { } /** - * {@note new} * Opens or creates a file, returning a file channel to access the file. * *

    The {@code options} parameter determines how the file is opened. @@ -293,7 +290,6 @@ private static final FileAttribute[] NO_ATTRIBUTES = new FileAttribute[0]; /** - * {@note new} * Opens or creates a file, returning a file channel to access the file. * *

    An invocation of this method behaves in exactly the same way as the diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/nio/channels/FileLock.java --- a/jdk/src/share/classes/java/nio/channels/FileLock.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/nio/channels/FileLock.java Wed Jul 05 16:59:43 2017 +0200 @@ -114,7 +114,6 @@ * @author Mark Reinhold * @author JSR-51 Expert Group * @since 1.4 - * @updated 1.7 */ public abstract class FileLock { @@ -161,7 +160,7 @@ } /** - * {@note new} Initializes a new instance of this class. + * Initializes a new instance of this class. * * @param channel * The channel upon whose file this lock is held @@ -199,7 +198,6 @@ } /** - * {@note revised} * Returns the file channel upon whose file this lock was acquired. * *

    This method has been superseded by the {@link #acquiredBy acquiredBy} @@ -213,7 +211,6 @@ } /** - * {@note new} * Returns the channel upon whose file this lock was acquired. * * @return The channel upon whose file this lock was acquired. diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/nio/channels/exceptions --- a/jdk/src/share/classes/java/nio/channels/exceptions Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/nio/channels/exceptions Wed Jul 05 16:59:43 2017 +0200 @@ -190,5 +190,5 @@ gen ShutdownChannelGroupException " * Unchecked exception thrown when an attempt is made to construct a channel in * a group that is shutdown or the completion handler for an I/O operation - * cannot be invoked because the channel group is shutdown." \ + * cannot be invoked because the channel group has terminated." \ -3903801676350154157L diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/nio/channels/package-info.java --- a/jdk/src/share/classes/java/nio/channels/package-info.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/nio/channels/package-info.java Wed Jul 05 16:59:43 2017 +0200 @@ -285,7 +285,6 @@ * java.lang.NullPointerException NullPointerException} to be thrown. * * @since 1.4 - * @updated 1.7 * @author Mark Reinhold * @author JSR-51 Expert Group */ diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/nio/file/FileRef.java --- a/jdk/src/share/classes/java/nio/file/FileRef.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/nio/file/FileRef.java Wed Jul 05 16:59:43 2017 +0200 @@ -39,8 +39,6 @@ * metadata or file attributes. * * @since 1.7 - * @see java.io.Inputs - * @see java.io.Outputs * @see java.nio.file.attribute.Attributes * @see java.io.File#toPath */ diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/java/util/Scanner.java --- a/jdk/src/share/classes/java/util/Scanner.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/java/util/Scanner.java Wed Jul 05 16:59:43 2017 +0200 @@ -674,7 +674,6 @@ } /** - * {@note new} * Constructs a new Scanner that produces values scanned * from the specified file. Bytes from the file are converted into * characters using the underlying platform's @@ -694,7 +693,6 @@ } /** - * {@note new} * Constructs a new Scanner that produces values scanned * from the specified file. Bytes from the file are converted into * characters using the specified charset. diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/sun/nio/ch/AbstractFuture.java --- a/jdk/src/share/classes/sun/nio/ch/AbstractFuture.java Tue Sep 01 23:44:41 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -package sun.nio.ch; - -import java.nio.channels.AsynchronousChannel; -import java.util.concurrent.Future; - -/** - * Base implementation of Future used for asynchronous I/O - */ - -abstract class AbstractFuture - implements Future -{ - private final AsynchronousChannel channel; - private final A attachment; - - protected AbstractFuture(AsynchronousChannel channel, A attachment) { - this.channel = channel; - this.attachment = attachment; - } - - final AsynchronousChannel channel() { - return channel; - } - - final A attachment() { - return attachment; - } - - /** - * Returns the result of the operation if it has completed successfully. - */ - abstract V value(); - - /** - * Returns the exception if the operation has failed. - */ - abstract Throwable exception(); -} diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java --- a/jdk/src/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java Wed Jul 05 16:59:43 2017 +0200 @@ -32,8 +32,8 @@ import java.io.FileDescriptor; import java.util.Queue; import java.util.concurrent.*; -import java.util.concurrent.locks.*; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicBoolean; import java.security.PrivilegedAction; import java.security.AccessController; import java.security.AccessControlContext; @@ -65,11 +65,8 @@ private final Queue taskQueue; // group shutdown - // shutdownLock is RW lock so as to allow for concurrent queuing of tasks - // when using a fixed thread pool. - private final ReadWriteLock shutdownLock = new ReentrantReadWriteLock(); + private final AtomicBoolean shutdown = new AtomicBoolean(); private final Object shutdownNowLock = new Object(); - private volatile boolean shutdown; private volatile boolean terminateInitiated; AsynchronousChannelGroupImpl(AsynchronousChannelProvider provider, @@ -214,7 +211,7 @@ @Override public final boolean isShutdown() { - return shutdown; + return shutdown.get(); } @Override @@ -260,17 +257,10 @@ @Override public final void shutdown() { - shutdownLock.writeLock().lock(); - try { - if (shutdown) { - // already shutdown - return; - } - shutdown = true; - } finally { - shutdownLock.writeLock().unlock(); + if (shutdown.getAndSet(true)) { + // already shutdown + return; } - // if there are channels in the group then shutdown will continue // when the last channel is closed if (!isEmpty()) { @@ -289,12 +279,7 @@ @Override public final void shutdownNow() throws IOException { - shutdownLock.writeLock().lock(); - try { - shutdown = true; - } finally { - shutdownLock.writeLock().unlock(); - } + shutdown.set(true); synchronized (shutdownNowLock) { if (!terminateInitiated) { terminateInitiated = true; @@ -305,6 +290,18 @@ } } + /** + * For use by AsynchronousFileChannel to release resources without shutting + * down the thread pool. + */ + final void detachFromThreadPool() { + if (shutdown.getAndSet(true)) + throw new AssertionError("Already shutdown"); + if (!isEmpty()) + throw new AssertionError("Group not empty"); + shutdownHandlerTasks(); + } + @Override public final boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java --- a/jdk/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java Wed Jul 05 16:59:43 2017 +0200 @@ -25,8 +25,10 @@ package sun.nio.ch; +import java.nio.ByteBuffer; import java.nio.channels.*; import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; import java.util.concurrent.locks.*; import java.io.FileDescriptor; import java.io.IOException; @@ -101,6 +103,33 @@ // -- file locking -- + abstract Future implLock(long position, + long size, + boolean shared, + A attachment, + CompletionHandler handler); + + @Override + public final Future lock(long position, + long size, + boolean shared) + + { + return implLock(position, size, shared, null, null); + } + + @Override + public final void lock(long position, + long size, + boolean shared, + A attachment, + CompletionHandler handler) + { + if (handler == null) + throw new NullPointerException("'handler' is null"); + implLock(position, size, shared, attachment, handler); + } + private volatile FileLockTable fileLockTable; final void ensureFileLockTableInitialized() throws IOException { @@ -175,4 +204,50 @@ end(); } } + + + // -- reading and writing -- + + abstract Future implRead(ByteBuffer dst, + long position, + A attachment, + CompletionHandler handler); + + @Override + public final Future read(ByteBuffer dst, long position) { + return implRead(dst, position, null, null); + } + + @Override + public final void read(ByteBuffer dst, + long position, + A attachment, + CompletionHandler handler) + { + if (handler == null) + throw new NullPointerException("'handler' is null"); + implRead(dst, position, attachment, handler); + } + + abstract Future implWrite(ByteBuffer src, + long position, + A attachment, + CompletionHandler handler); + + + @Override + public final Future write(ByteBuffer src, long position) { + return implWrite(src, position, null, null); + } + + @Override + public final void write(ByteBuffer src, + long position, + A attachment, + CompletionHandler handler) + { + if (handler == null) + throw new NullPointerException("'handler' is null"); + implWrite(src, position, attachment, handler); + } } diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java --- a/jdk/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java Wed Jul 05 16:59:43 2017 +0200 @@ -35,6 +35,7 @@ import java.util.Set; import java.util.HashSet; import java.util.Collections; +import java.util.concurrent.Future; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import sun.net.NetHooks; @@ -108,6 +109,29 @@ implClose(); } + /** + * Invoked by accept to accept connection + */ + abstract Future + implAccept(Object attachment, + CompletionHandler handler); + + + @Override + public final Future accept() { + return implAccept(null, null); + } + + @Override + @SuppressWarnings("unchecked") + public final void accept(A attachment, + CompletionHandler handler) + { + if (handler == null) + throw new NullPointerException("'handler' is null"); + implAccept(attachment, (CompletionHandler)handler); + } + final boolean isAcceptKilled() { return acceptKilled; } diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java --- a/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java Wed Jul 05 16:59:43 2017 +0200 @@ -184,28 +184,53 @@ } /** + * Invoked by connect to initiate the connect operation. + */ + abstract Future implConnect(SocketAddress remote, + A attachment, + CompletionHandler handler); + + @Override + public final Future connect(SocketAddress remote) { + return implConnect(remote, null, null); + } + + @Override + public final void connect(SocketAddress remote, + A attachment, + CompletionHandler handler) + { + if (handler == null) + throw new NullPointerException("'handler' is null"); + implConnect(remote, attachment, handler); + } + + /** * Invoked by read to initiate the I/O operation. */ - abstract Future readImpl(ByteBuffer[] dsts, - boolean isScatteringRead, + abstract Future implRead(boolean isScatteringRead, + ByteBuffer dst, + ByteBuffer[] dsts, long timeout, TimeUnit unit, A attachment, CompletionHandler handler); @SuppressWarnings("unchecked") - private Future read(ByteBuffer[] dsts, - boolean isScatteringRead, + private Future read(boolean isScatteringRead, + ByteBuffer dst, + ByteBuffer[] dsts, long timeout, TimeUnit unit, - A attachment, + A att, CompletionHandler handler) { if (!isOpen()) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invoke(handler, result); - return result; + Throwable e = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(e); + Invoker.invoke(this, handler, att, null, e); + return null; } if (remoteAddress == null) @@ -213,13 +238,13 @@ if (timeout < 0L) throw new IllegalArgumentException("Negative timeout"); - boolean hasSpaceToRead = isScatteringRead || dsts[0].hasRemaining(); + boolean hasSpaceToRead = isScatteringRead || dst.hasRemaining(); boolean shutdown = false; // check and update state synchronized (readLock) { if (readKilled) - throw new RuntimeException("Reading not allowed due to timeout or cancellation"); + throw new IllegalStateException("Reading not allowed due to timeout or cancellation"); if (reading) throw new ReadPendingException(); if (readShutdown) { @@ -234,44 +259,53 @@ // immediately complete with -1 if shutdown for read // immediately complete with 0 if no space remaining if (shutdown || !hasSpaceToRead) { - CompletedFuture result; + Number result; if (isScatteringRead) { - Long value = (shutdown) ? Long.valueOf(-1L) : Long.valueOf(0L); - result = (CompletedFuture)CompletedFuture.withResult(this, value, attachment); + result = (shutdown) ? Long.valueOf(-1L) : Long.valueOf(0L); } else { - int value = (shutdown) ? -1 : 0; - result = (CompletedFuture)CompletedFuture.withResult(this, value, attachment); + result = (shutdown) ? -1 : 0; } - Invoker.invoke(handler, result); - return result; + if (handler == null) + return CompletedFuture.withResult((V)result); + Invoker.invoke(this, handler, att, (V)result, null); + return null; } - return readImpl(dsts, isScatteringRead, timeout, unit, attachment, handler); + return implRead(isScatteringRead, dst, dsts, timeout, unit, att, handler); + } + + @Override + public final Future read(ByteBuffer dst) { + if (dst.isReadOnly()) + throw new IllegalArgumentException("Read-only buffer"); + return read(false, dst, null, 0L, TimeUnit.MILLISECONDS, null, null); } @Override - public final Future read(ByteBuffer dst, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler) + public final void read(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler) { + if (handler == null) + throw new NullPointerException("'handler' is null"); if (dst.isReadOnly()) throw new IllegalArgumentException("Read-only buffer"); - ByteBuffer[] bufs = new ByteBuffer[1]; - bufs[0] = dst; - return read(bufs, false, timeout, unit, attachment, handler); + read(false, dst, null, timeout, unit, attachment, handler); } @Override - public final Future read(ByteBuffer[] dsts, - int offset, - int length, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler) + public final void read(ByteBuffer[] dsts, + int offset, + int length, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler) { + if (handler == null) + throw new NullPointerException("'handler' is null"); if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) throw new IndexOutOfBoundsException(); ByteBuffer[] bufs = Util.subsequence(dsts, offset, length); @@ -279,39 +313,41 @@ if (bufs[i].isReadOnly()) throw new IllegalArgumentException("Read-only buffer"); } - return read(bufs, true, timeout, unit, attachment, handler); + read(true, null, bufs, timeout, unit, attachment, handler); } /** * Invoked by write to initiate the I/O operation. */ - abstract Future writeImpl(ByteBuffer[] srcs, - boolean isGatheringWrite, + abstract Future implWrite(boolean isGatheringWrite, + ByteBuffer src, + ByteBuffer[] srcs, long timeout, TimeUnit unit, A attachment, CompletionHandler handler); @SuppressWarnings("unchecked") - private Future write(ByteBuffer[] srcs, - boolean isGatheringWrite, + private Future write(boolean isGatheringWrite, + ByteBuffer src, + ByteBuffer[] srcs, long timeout, TimeUnit unit, - A attachment, + A att, CompletionHandler handler) { - boolean hasDataToWrite = isGatheringWrite || srcs[0].hasRemaining(); + boolean hasDataToWrite = isGatheringWrite || src.hasRemaining(); boolean closed = false; if (isOpen()) { if (remoteAddress == null) throw new NotYetConnectedException(); - if (timeout < 0L) + if (timeout < 0L) throw new IllegalArgumentException("Negative timeout"); // check and update state synchronized (writeLock) { if (writeKilled) - throw new RuntimeException("Writing not allowed due to timeout or cancellation"); + throw new IllegalStateException("Writing not allowed due to timeout or cancellation"); if (writing) throw new WritePendingException(); if (writeShutdown) { @@ -327,52 +363,57 @@ // channel is closed or shutdown for write if (closed) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invoke(handler, result); - return result; + Throwable e = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(e); + Invoker.invoke(this, handler, att, null, e); + return null; } // nothing to write so complete immediately if (!hasDataToWrite) { - CompletedFuture result; - if (isGatheringWrite) { - result = (CompletedFuture)CompletedFuture.withResult(this, 0L, attachment); - } else { - result = (CompletedFuture)CompletedFuture.withResult(this, 0, attachment); - } - Invoker.invoke(handler, result); - return result; + Number result = (isGatheringWrite) ? (Number)0L : (Number)0; + if (handler == null) + return CompletedFuture.withResult((V)result); + Invoker.invoke(this, handler, att, (V)result, null); + return null; } - return writeImpl(srcs, isGatheringWrite, timeout, unit, attachment, handler); + return implWrite(isGatheringWrite, src, srcs, timeout, unit, att, handler); + } + + @Override + public final Future write(ByteBuffer src) { + return write(false, src, null, 0L, TimeUnit.MILLISECONDS, null, null); } @Override - public final Future write(ByteBuffer src, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler) + public final void write(ByteBuffer src, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler) { - ByteBuffer[] bufs = new ByteBuffer[1]; - bufs[0] = src; - return write(bufs, false, timeout, unit, attachment, handler); + if (handler == null) + throw new NullPointerException("'handler' is null"); + write(false, src, null, timeout, unit, attachment, handler); } @Override - public final Future write(ByteBuffer[] srcs, - int offset, - int length, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler) + public final void write(ByteBuffer[] srcs, + int offset, + int length, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler) { + if (handler == null) + throw new NullPointerException("'handler' is null"); if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) throw new IndexOutOfBoundsException(); srcs = Util.subsequence(srcs, offset, length); - return write(srcs, true, timeout, unit, attachment, handler); + write(true, null, srcs, timeout, unit, attachment, handler); } @Override @@ -461,7 +502,6 @@ } @Override - @SuppressWarnings("unchecked") public final SocketAddress getRemoteAddress() throws IOException { if (!isOpen()) throw new ClosedChannelException(); diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/sun/nio/ch/CompletedFuture.java --- a/jdk/src/share/classes/sun/nio/ch/CompletedFuture.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/sun/nio/ch/CompletedFuture.java Wed Jul 05 16:59:43 2017 +0200 @@ -25,7 +25,7 @@ package sun.nio.ch; -import java.nio.channels.AsynchronousChannel; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.ExecutionException; import java.io.IOException; @@ -35,39 +35,35 @@ * completed. */ -final class CompletedFuture - extends AbstractFuture -{ +final class CompletedFuture implements Future { private final V result; private final Throwable exc; - private CompletedFuture(AsynchronousChannel channel, - V result, - Throwable exc, - A attachment) - { - super(channel, attachment); + private CompletedFuture(V result, Throwable exc) { this.result = result; this.exc = exc; } @SuppressWarnings("unchecked") - static CompletedFuture withResult(AsynchronousChannel channel, - V result, - A attachment) - { - return new CompletedFuture(channel, result, null, attachment); + static CompletedFuture withResult(V result) { + return new CompletedFuture(result, null); } @SuppressWarnings("unchecked") - static CompletedFuture withFailure(AsynchronousChannel channel, - Throwable exc, - A attachment) - { + static CompletedFuture withFailure(Throwable exc) { // exception must be IOException or SecurityException if (!(exc instanceof IOException) && !(exc instanceof SecurityException)) exc = new IOException(exc); - return new CompletedFuture(channel, null, exc, attachment); + return new CompletedFuture(null, exc); + } + + @SuppressWarnings("unchecked") + static CompletedFuture withResult(V result, Throwable exc) { + if (exc == null) { + return withResult(result); + } else { + return withFailure(exc); + } } @Override @@ -100,14 +96,4 @@ public boolean cancel(boolean mayInterruptIfRunning) { return false; } - - @Override - Throwable exception() { - return exc; - } - - @Override - V value() { - return result; - } } diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/sun/nio/ch/Invoker.java --- a/jdk/src/share/classes/sun/nio/ch/Invoker.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/sun/nio/ch/Invoker.java Wed Jul 05 16:59:43 2017 +0200 @@ -117,33 +117,32 @@ * Invoke handler without checking the thread identity or number of handlers * on the thread stack. */ - @SuppressWarnings("unchecked") static void invokeUnchecked(CompletionHandler handler, - AbstractFuture result) + A attachment, + V value, + Throwable exc) { - if (handler != null && !result.isCancelled()) { - Throwable exc = result.exception(); - if (exc == null) { - handler.completed(result.value(), result.attachment()); - } else { - handler.failed(exc, result.attachment()); - } + if (exc == null) { + handler.completed(value, attachment); + } else { + handler.failed(exc, attachment); + } - // clear interrupt - Thread.interrupted(); - } + // clear interrupt + Thread.interrupted(); } - /** - * Invoke handler after incrementing the invoke count. + * Invoke handler assuming thread identity already checked */ static void invokeDirect(GroupAndInvokeCount myGroupAndInvokeCount, CompletionHandler handler, - AbstractFuture result) + A attachment, + V result, + Throwable exc) { myGroupAndInvokeCount.incrementInvokeCount(); - invokeUnchecked(handler, result); + Invoker.invokeUnchecked(handler, attachment, result, exc); } /** @@ -151,64 +150,64 @@ * thread pool then the handler is invoked directly, otherwise it is * invoked indirectly. */ - static void invoke(CompletionHandler handler, - AbstractFuture result) + static void invoke(AsynchronousChannel channel, + CompletionHandler handler, + A attachment, + V result, + Throwable exc) { - if (handler != null) { - boolean invokeDirect = false; - boolean identityOkay = false; - GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get(); - if (thisGroupAndInvokeCount != null) { - AsynchronousChannel channel = result.channel(); - if ((thisGroupAndInvokeCount.group() == ((Groupable)channel).group())) - identityOkay = true; - if (identityOkay && - (thisGroupAndInvokeCount.invokeCount() < maxHandlerInvokeCount)) - { - // group match - invokeDirect = true; - } + boolean invokeDirect = false; + boolean identityOkay = false; + GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get(); + if (thisGroupAndInvokeCount != null) { + if ((thisGroupAndInvokeCount.group() == ((Groupable)channel).group())) + identityOkay = true; + if (identityOkay && + (thisGroupAndInvokeCount.invokeCount() < maxHandlerInvokeCount)) + { + // group match + invokeDirect = true; } - if (invokeDirect) { - thisGroupAndInvokeCount.incrementInvokeCount(); - invokeUnchecked(handler, result); - } else { - try { - invokeIndirectly(handler, result); - } catch (RejectedExecutionException ree) { - // channel group shutdown; fallback to invoking directly - // if the current thread has the right identity. - if (identityOkay) { - invokeUnchecked(handler, result); - } else { - throw new ShutdownChannelGroupException(); - } + } + if (invokeDirect) { + invokeDirect(thisGroupAndInvokeCount, handler, attachment, result, exc); + } else { + try { + invokeIndirectly(channel, handler, attachment, result, exc); + } catch (RejectedExecutionException ree) { + // channel group shutdown; fallback to invoking directly + // if the current thread has the right identity. + if (identityOkay) { + invokeDirect(thisGroupAndInvokeCount, + handler, attachment, result, exc); + } else { + throw new ShutdownChannelGroupException(); } } } } /** - * Invokes the handler "indirectly" in the channel group's thread pool. + * Invokes the handler indirectly via the channel group's thread pool. */ - static void invokeIndirectly(final CompletionHandler handler, - final AbstractFuture result) + static void invokeIndirectly(AsynchronousChannel channel, + final CompletionHandler handler, + final A attachment, + final V result, + final Throwable exc) { - if (handler != null) { - AsynchronousChannel channel = result.channel(); - try { - ((Groupable)channel).group().executeOnPooledThread(new Runnable() { - public void run() { - GroupAndInvokeCount thisGroupAndInvokeCount = - myGroupAndInvokeCount.get(); - if (thisGroupAndInvokeCount != null) - thisGroupAndInvokeCount.setInvokeCount(1); - invokeUnchecked(handler, result); - } - }); - } catch (RejectedExecutionException ree) { - throw new ShutdownChannelGroupException(); - } + try { + ((Groupable)channel).group().executeOnPooledThread(new Runnable() { + public void run() { + GroupAndInvokeCount thisGroupAndInvokeCount = + myGroupAndInvokeCount.get(); + if (thisGroupAndInvokeCount != null) + thisGroupAndInvokeCount.setInvokeCount(1); + invokeUnchecked(handler, attachment, result, exc); + } + }); + } catch (RejectedExecutionException ree) { + throw new ShutdownChannelGroupException(); } } @@ -216,19 +215,19 @@ * Invokes the handler "indirectly" in the given Executor */ static void invokeIndirectly(final CompletionHandler handler, - final AbstractFuture result, + final A attachment, + final V value, + final Throwable exc, Executor executor) { - if (handler != null) { - try { - executor.execute(new Runnable() { - public void run() { - invokeUnchecked(handler, result); - } - }); - } catch (RejectedExecutionException ree) { - throw new ShutdownChannelGroupException(); - } + try { + executor.execute(new Runnable() { + public void run() { + invokeUnchecked(handler, attachment, value, exc); + } + }); + } catch (RejectedExecutionException ree) { + throw new ShutdownChannelGroupException(); } } @@ -258,4 +257,52 @@ throw new ShutdownChannelGroupException(); } } + + /** + * Invoke handler with completed result. This method does not check the + * thread identity or the number of handlers on the thread stack. + */ + static void invokeUnchecked(PendingFuture future) { + assert future.isDone(); + CompletionHandler handler = future.handler(); + if (handler != null) { + invokeUnchecked(handler, + future.attachment(), + future.value(), + future.exception()); + } + } + + /** + * Invoke handler with completed result. If the current thread is in the + * channel group's thread pool then the handler is invoked directly, + * otherwise it is invoked indirectly. + */ + static void invoke(PendingFuture future) { + assert future.isDone(); + CompletionHandler handler = future.handler(); + if (handler != null) { + invoke(future.channel(), + handler, + future.attachment(), + future.value(), + future.exception()); + } + } + + /** + * Invoke handler with completed result. The handler is invoked indirectly, + * via the channel group's thread pool. + */ + static void invokeIndirectly(PendingFuture future) { + assert future.isDone(); + CompletionHandler handler = future.handler(); + if (handler != null) { + invokeIndirectly(future.channel(), + handler, + future.attachment(), + future.value(), + future.exception()); + } + } } diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/sun/nio/ch/PendingFuture.java --- a/jdk/src/share/classes/sun/nio/ch/PendingFuture.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/sun/nio/ch/PendingFuture.java Wed Jul 05 16:59:43 2017 +0200 @@ -34,13 +34,13 @@ * attachment of an additional arbitrary context object and a timer task. */ -final class PendingFuture - extends AbstractFuture -{ +final class PendingFuture implements Future { private static final CancellationException CANCELLED = new CancellationException(); + private final AsynchronousChannel channel; private final CompletionHandler handler; + private final A attachment; // true if result (or exception) is available private volatile boolean haveResult; @@ -56,14 +56,14 @@ // optional context object private volatile Object context; - PendingFuture(AsynchronousChannel channel, CompletionHandler handler, A attachment, Object context) { - super(channel, attachment); + this.channel = channel; this.handler = handler; + this.attachment = attachment; this.context = context; } @@ -71,14 +71,31 @@ CompletionHandler handler, A attachment) { - super(channel, attachment); + this.channel = channel; this.handler = handler; + this.attachment = attachment; + } + + PendingFuture(AsynchronousChannel channel) { + this(channel, null, null); + } + + PendingFuture(AsynchronousChannel channel, Object context) { + this(channel, null, null, context); + } + + AsynchronousChannel channel() { + return channel; } CompletionHandler handler() { return handler; } + A attachment() { + return attachment; + } + void setContext(Object context) { this.context = context; } @@ -113,36 +130,45 @@ /** * Sets the result, or a no-op if the result or exception is already set. */ - boolean setResult(V res) { + void setResult(V res) { synchronized (this) { if (haveResult) - return false; + return; result = res; haveResult = true; if (timeoutTask != null) timeoutTask.cancel(false); if (latch != null) latch.countDown(); - return true; } } /** * Sets the result, or a no-op if the result or exception is already set. */ - boolean setFailure(Throwable x) { + void setFailure(Throwable x) { if (!(x instanceof IOException) && !(x instanceof SecurityException)) x = new IOException(x); synchronized (this) { if (haveResult) - return false; + return; exc = x; haveResult = true; if (timeoutTask != null) timeoutTask.cancel(false); if (latch != null) latch.countDown(); - return true; + } + } + + /** + * Sets the result + */ + void setResult(V res, Throwable x) { + if (x == null) { + setResult(res); + } else { + setFailure(x); } } @@ -178,12 +204,10 @@ return result; } - @Override Throwable exception() { return (exc != CANCELLED) ? exc : null; } - @Override V value() { return result; } @@ -204,33 +228,6 @@ if (haveResult) return false; // already completed - // A shutdown of the channel group will close all channels and - // shutdown the executor. To ensure that the completion handler - // is executed we queue the task while holding the lock. - if (handler != null) { - prepareForWait(); - Runnable cancelTask = new Runnable() { - public void run() { - while (!haveResult) { - try { - latch.await(); - } catch (InterruptedException ignore) { } - } - handler.cancelled(attachment()); - } - }; - AsynchronousChannel ch = channel(); - if (ch instanceof Groupable) { - ((Groupable)ch).group().executeOnPooledThread(cancelTask); - } else { - if (ch instanceof AsynchronousFileChannelImpl) { - ((AsynchronousFileChannelImpl)ch).executor().execute(cancelTask); - } else { - throw new AssertionError("Should not get here"); - } - } - } - // notify channel if (channel() instanceof Cancellable) ((Cancellable)channel()).onCancel(this); @@ -249,7 +246,7 @@ } catch (IOException ignore) { } } - // release waiters (this also releases the invoker) + // release waiters if (latch != null) latch.countDown(); return true; diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java --- a/jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java Wed Jul 05 16:59:43 2017 +0200 @@ -317,51 +317,71 @@ return new WrappedMembershipKey(this, key); } - @Override - public Future send(ByteBuffer src, - SocketAddress target, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler) + private Future implSend(ByteBuffer src, + SocketAddress target, + A attachment, + CompletionHandler handler) { - if (timeout < 0L) - throw new IllegalArgumentException("Negative timeout"); - if (unit == null) - throw new NullPointerException(); - - CompletedFuture result; + int n = 0; + Throwable exc = null; try { - int n = dc.send(src, target); - result = CompletedFuture.withResult(this, n, attachment); + n = dc.send(src, target); } catch (IOException ioe) { - result = CompletedFuture.withFailure(this, ioe, attachment); + exc = ioe; } - Invoker.invoke(handler, result); - return result; + if (handler == null) + return CompletedFuture.withResult(n, exc); + Invoker.invoke(this, handler, attachment, n, exc); + return null; + } + + @Override + public Future send(ByteBuffer src, SocketAddress target) { + return implSend(src, target, null, null); } @Override - public Future write(ByteBuffer src, - long timeout, - TimeUnit unit, - A attachment, - CompletionHandler handler) + public void send(ByteBuffer src, + SocketAddress target, + A attachment, + CompletionHandler handler) + { + if (handler == null) + throw new NullPointerException("'handler' is null"); + implSend(src, target, attachment, handler); + } + + private Future implWrite(ByteBuffer src, + A attachment, + CompletionHandler handler) { - if (timeout < 0L) - throw new IllegalArgumentException("Negative timeout"); - if (unit == null) - throw new NullPointerException(); - - CompletedFuture result; + int n = 0; + Throwable exc = null; try { - int n = dc.write(src); - result = CompletedFuture.withResult(this, n, attachment); + n = dc.write(src); } catch (IOException ioe) { - result = CompletedFuture.withFailure(this, ioe, attachment); + exc = ioe; } - Invoker.invoke(handler, result); - return result; + if (handler == null) + return CompletedFuture.withResult(n, exc); + Invoker.invoke(this, handler, attachment, n, exc); + return null; + + } + + @Override + public Future write(ByteBuffer src) { + return implWrite(src, null, null); + } + + @Override + public void write(ByteBuffer src, + A attachment, + CompletionHandler handler) + { + if (handler == null) + throw new NullPointerException("'handler' is null"); + implWrite(src, attachment, handler); } /** @@ -390,12 +410,11 @@ } } - @Override - public Future receive(final ByteBuffer dst, - final long timeout, - final TimeUnit unit, - A attachment, - final CompletionHandler handler) + private Future implReceive(final ByteBuffer dst, + final long timeout, + final TimeUnit unit, + A attachment, + final CompletionHandler handler) { if (dst.isReadOnly()) throw new IllegalArgumentException("Read-only buffer"); @@ -406,10 +425,11 @@ // complete immediately if channel closed if (!isOpen()) { - CompletedFuture result = CompletedFuture.withFailure(this, - new ClosedChannelException(), attachment); - Invoker.invoke(handler, result); - return result; + Throwable exc = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(exc); + Invoker.invoke(this, handler, attachment, null, exc); + return null; } final AccessControlContext acc = (System.getSecurityManager() == null) ? @@ -471,7 +491,7 @@ x = new AsynchronousCloseException(); result.setFailure(x); } - Invoker.invokeUnchecked(handler, result); + Invoker.invokeUnchecked(result); } }; try { @@ -483,11 +503,27 @@ } @Override - public Future read(final ByteBuffer dst, - final long timeout, - final TimeUnit unit, - A attachment, - final CompletionHandler handler) + public Future receive(ByteBuffer dst) { + return implReceive(dst, 0L, TimeUnit.MILLISECONDS, null, null); + } + + @Override + public void receive(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler) + { + if (handler == null) + throw new NullPointerException("'handler' is null"); + implReceive(dst, timeout, unit, attachment, handler); + } + + private Future implRead(final ByteBuffer dst, + final long timeout, + final TimeUnit unit, + A attachment, + final CompletionHandler handler) { if (dst.isReadOnly()) throw new IllegalArgumentException("Read-only buffer"); @@ -495,18 +531,20 @@ throw new IllegalArgumentException("Negative timeout"); if (unit == null) throw new NullPointerException(); - // another thread may disconnect before read is initiated - if (!dc.isConnected()) - throw new NotYetConnectedException(); // complete immediately if channel closed if (!isOpen()) { - CompletedFuture result = CompletedFuture.withFailure(this, - new ClosedChannelException(), attachment); - Invoker.invoke(handler, result); - return result; + Throwable exc = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(exc); + Invoker.invoke(this, handler, attachment, null, exc); + return null; } + // another thread may disconnect before read is initiated + if (!dc.isConnected()) + throw new NotYetConnectedException(); + final PendingFuture result = new PendingFuture(this, handler, attachment); Runnable task = new Runnable() { @@ -563,7 +601,7 @@ x = new AsynchronousCloseException(); result.setFailure(x); } - Invoker.invokeUnchecked(handler, result); + Invoker.invokeUnchecked(result); } }; try { @@ -575,6 +613,23 @@ } @Override + public Future read(ByteBuffer dst) { + return implRead(dst, 0L, TimeUnit.MILLISECONDS, null, null); + } + + @Override + public void read(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler) + { + if (handler == null) + throw new NullPointerException("'handler' is null"); + implRead(dst, timeout, unit, attachment, handler); + } + + @Override public AsynchronousDatagramChannel bind(SocketAddress local) throws IOException { diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java --- a/jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java Wed Jul 05 16:59:43 2017 +0200 @@ -50,9 +50,6 @@ // Used to make native read and write calls private static final FileDispatcher nd = new FileDispatcherImpl(); - // indicates if the associated thread pool is the default thread pool - private final boolean isDefaultExecutor; - // Thread-safe set of IDs of native threads, for signalling private final NativeThreadSet threads = new NativeThreadSet(2); @@ -60,11 +57,9 @@ SimpleAsynchronousFileChannelImpl(FileDescriptor fdObj, boolean reading, boolean writing, - ExecutorService executor, - boolean isDefaultexecutor) + ExecutorService executor) { super(fdObj, reading, writing, executor); - this.isDefaultExecutor = isDefaultexecutor; } public static AsynchronousFileChannel open(FileDescriptor fdo, @@ -73,17 +68,9 @@ ThreadPool pool) { // Executor is either default or based on pool parameters - ExecutorService executor; - boolean isDefaultexecutor; - if (pool == null) { - executor = DefaultExecutorHolder.defaultExecutor; - isDefaultexecutor = true; - } else { - executor = pool.executor(); - isDefaultexecutor = false; - } - return new SimpleAsynchronousFileChannelImpl(fdo, - reading, writing, executor, isDefaultexecutor); + ExecutorService executor = (pool == null) ? + DefaultExecutorHolder.defaultExecutor : pool.executor(); + return new SimpleAsynchronousFileChannelImpl(fdo, reading, writing, executor); } @Override @@ -114,16 +101,6 @@ // close file nd.close(fdObj); - - // shutdown executor if specific to this channel - if (!isDefaultExecutor) { - AccessController.doPrivileged(new PrivilegedAction() { - public Void run() { - executor.shutdown(); - return null; - } - }); - } } @Override @@ -194,11 +171,11 @@ } @Override - public Future lock(final long position, - final long size, - final boolean shared, - A attachment, - final CompletionHandler handler) + Future implLock(final long position, + final long size, + final boolean shared, + final A attachment, + final CompletionHandler handler) { if (shared && !reading) throw new NonReadableChannelException(); @@ -208,16 +185,19 @@ // add to lock table final FileLockImpl fli = addToFileLockTable(position, size, shared); if (fli == null) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invokeIndirectly(handler, result, executor); - return result; + Throwable exc = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(exc); + Invoker.invokeIndirectly(handler, attachment, null, exc, executor); + return null; } - final PendingFuture result = - new PendingFuture(this, handler, attachment); + final PendingFuture result = (handler == null) ? + new PendingFuture(this) : null; Runnable task = new Runnable() { public void run() { + Throwable exc = null; + int ti = threads.add(); try { int n; @@ -226,31 +206,36 @@ do { n = nd.lock(fdObj, true, position, size, shared); } while ((n == FileDispatcher.INTERRUPTED) && isOpen()); - if (n == FileDispatcher.LOCKED && isOpen()) { - result.setResult(fli); - } else { + if (n != FileDispatcher.LOCKED || !isOpen()) { throw new AsynchronousCloseException(); } } catch (IOException x) { removeFromFileLockTable(fli); if (!isOpen()) x = new AsynchronousCloseException(); - result.setFailure(x); + exc = x; } finally { end(); } } finally { threads.remove(ti); } - Invoker.invokeUnchecked(handler, result); + if (handler == null) { + result.setResult(fli, exc); + } else { + Invoker.invokeUnchecked(handler, attachment, fli, exc); + } } }; + boolean executed = false; try { executor.execute(task); - } catch (RejectedExecutionException ree) { - // rollback - removeFromFileLockTable(fli); - throw new ShutdownChannelGroupException(); + executed = true; + } finally { + if (!executed) { + // rollback + removeFromFileLockTable(fli); + } } return result; } @@ -301,10 +286,10 @@ } @Override - public Future read(final ByteBuffer dst, - final long position, - A attachment, - final CompletionHandler handler) + Future implRead(final ByteBuffer dst, + final long position, + final A attachment, + final CompletionHandler handler) { if (position < 0) throw new IllegalArgumentException("Negative position"); @@ -315,55 +300,52 @@ // complete immediately if channel closed or no space remaining if (!isOpen() || (dst.remaining() == 0)) { - CompletedFuture result; - if (isOpen()) { - result = CompletedFuture.withResult(this, 0, attachment); - } else { - result = CompletedFuture.withFailure(this, - new ClosedChannelException(), attachment); - } - Invoker.invokeIndirectly(handler, result, executor); - return result; + Throwable exc = (isOpen()) ? null : new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withResult(0, exc); + Invoker.invokeIndirectly(handler, attachment, 0, exc, executor); + return null; } - final PendingFuture result = - new PendingFuture(this, handler, attachment); + final PendingFuture result = (handler == null) ? + new PendingFuture(this) : null; Runnable task = new Runnable() { public void run() { + int n = 0; + Throwable exc = null; + int ti = threads.add(); try { begin(); - int n; do { n = IOUtil.read(fdObj, dst, position, nd, null); } while ((n == IOStatus.INTERRUPTED) && isOpen()); if (n < 0 && !isOpen()) throw new AsynchronousCloseException(); - result.setResult(n); } catch (IOException x) { if (!isOpen()) x = new AsynchronousCloseException(); - result.setFailure(x); + exc = x; } finally { end(); threads.remove(ti); } - Invoker.invokeUnchecked(handler, result); + if (handler == null) { + result.setResult(n, exc); + } else { + Invoker.invokeUnchecked(handler, attachment, n, exc); + } } }; - try { - executor.execute(task); - } catch (RejectedExecutionException ree) { - throw new ShutdownChannelGroupException(); - } + executor.execute(task); return result; } @Override - public Future write(final ByteBuffer src, - final long position, - A attachment, - final CompletionHandler handler) + Future implWrite(final ByteBuffer src, + final long position, + final A attachment, + final CompletionHandler handler) { if (position < 0) throw new IllegalArgumentException("Negative position"); @@ -372,47 +354,44 @@ // complete immediately if channel is closed or no bytes remaining if (!isOpen() || (src.remaining() == 0)) { - CompletedFuture result; - if (isOpen()) { - result = CompletedFuture.withResult(this, 0, attachment); - } else { - result = CompletedFuture.withFailure(this, - new ClosedChannelException(), attachment); - } - Invoker.invokeIndirectly(handler, result, executor); - return result; + Throwable exc = (isOpen()) ? null : new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withResult(0, exc); + Invoker.invokeIndirectly(handler, attachment, 0, exc, executor); + return null; } - final PendingFuture result = - new PendingFuture(this, handler, attachment); + final PendingFuture result = (handler == null) ? + new PendingFuture(this) : null; Runnable task = new Runnable() { public void run() { + int n = 0; + Throwable exc = null; + int ti = threads.add(); try { begin(); - int n; do { n = IOUtil.write(fdObj, src, position, nd, null); } while ((n == IOStatus.INTERRUPTED) && isOpen()); if (n < 0 && !isOpen()) throw new AsynchronousCloseException(); - result.setResult(n); } catch (IOException x) { if (!isOpen()) x = new AsynchronousCloseException(); - result.setFailure(x); + exc = x; } finally { end(); threads.remove(ti); } - Invoker.invokeUnchecked(handler, result); + if (handler == null) { + result.setResult(n, exc); + } else { + Invoker.invokeUnchecked(handler, attachment, n, exc); + } } }; - try { - executor.execute(task); - } catch (RejectedExecutionException ree) { - throw new ShutdownChannelGroupException(); - } + executor.execute(task); return result; } } diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/sun/nio/cs/ext/ISO2022.java --- a/jdk/src/share/classes/sun/nio/cs/ext/ISO2022.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/sun/nio/cs/ext/ISO2022.java Wed Jul 05 16:59:43 2017 +0200 @@ -388,9 +388,9 @@ protected static class Encoder extends CharsetEncoder { private final Surrogate.Parser sgp = new Surrogate.Parser(); - private final byte SS2 = (byte)0x8e; - private final byte PLANE2 = (byte)0xA2; - private final byte PLANE3 = (byte)0xA3; + public static final byte SS2 = (byte)0x8e; + public static final byte PLANE2 = (byte)0xA2; + public static final byte PLANE3 = (byte)0xA3; private final byte MSB = (byte)0x80; protected final byte maximumDesignatorLength = 4; diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/sun/nio/cs/ext/ISO2022_CN_CNS.java --- a/jdk/src/share/classes/sun/nio/cs/ext/ISO2022_CN_CNS.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/sun/nio/cs/ext/ISO2022_CN_CNS.java Wed Jul 05 16:59:43 2017 +0200 @@ -76,6 +76,15 @@ } catch (Exception e) { } } + private byte[] bb = new byte[4]; + public boolean canEncode(char c) { + int n = 0; + return (c <= '\u007f' || + (n = ((EUC_TW.Encoder)ISOEncoder).toEUC(c, bb)) == 2 || + (n == 4 && bb[0] == SS2 && + (bb[1] == PLANE2 || bb[1] == PLANE3))); + } + /* * Since ISO2022-CN-CNS possesses a CharsetEncoder * without the corresponding CharsetDecoder half the diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/sun/security/jgss/SunProvider.java --- a/jdk/src/share/classes/sun/security/jgss/SunProvider.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/sun/security/jgss/SunProvider.java Wed Jul 05 16:59:43 2017 +0200 @@ -62,7 +62,7 @@ public SunProvider() { /* We are the Sun JGSS provider */ - super("SunJGSS", 1.0, INFO); + super("SunJGSS", 1.7d, INFO); AccessController.doPrivileged( new java.security.PrivilegedAction() { diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java --- a/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java Wed Jul 05 16:59:43 2017 +0200 @@ -41,6 +41,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.File; +import java.util.Comparator; import java.util.StringTokenizer; /** @@ -229,10 +230,11 @@ /** * Reads the service key from the keytab file. * @param service the PrincipalName of the requested service. - * @return the last service key in the keytab + * @return the last service key in the keytab with the highest kvno */ public EncryptionKey readServiceKey(PrincipalName service) { KeyTabEntry entry = null; + EncryptionKey key = null; if (entries != null) { // Find latest entry for this service that has an etype // that has been configured for use @@ -240,9 +242,12 @@ entry = entries.elementAt(i); if (entry.service.match(service)) { if (EType.isSupported(entry.keyType)) { - return new EncryptionKey(entry.keyblock, + if (key == null || + entry.keyVersion > key.getKeyVersionNumber()) { + key = new EncryptionKey(entry.keyblock, entry.keyType, new Integer(entry.keyVersion)); + } } else if (DEBUG) { System.out.println("Found unsupported keytype (" + entry.keyType + ") for " + service); @@ -250,12 +255,13 @@ } } } - return null; + return key; } /** * Reads all keys for a service from the keytab file that have - * etypes that have been configured for use. + * etypes that have been configured for use. If there are multiple + * keys with same etype, the one with the highest kvno is returned. * @param service the PrincipalName of the requested service * @return an array containing all the service keys */ @@ -288,49 +294,39 @@ size = keys.size(); if (size == 0) return null; - EncryptionKey[] retVal = new EncryptionKey[size]; + EncryptionKey[] retVal = keys.toArray(new EncryptionKey[size]); // Sort keys according to default_tkt_enctypes - int pos = 0; - EncryptionKey k; if (DEBUG) { System.out.println("Ordering keys wrt default_tkt_enctypes list"); } - int[] etypes = EType.getDefaults("default_tkt_enctypes"); - if (etypes == null || etypes == EType.getBuiltInDefaults()) { - // Either no supported types specified in default_tkt_enctypes - // or no default_tkt_enctypes entry at all. For both cases, - // just return supported keys in the order retrieved - for (int i = 0; i < size; i++) { - retVal[pos++] = keys.get(i); - } - } else { - for (int j = 0; j < etypes.length && pos < size; j++) { - int target = etypes[j]; - for (int i = 0; i < size && pos < size; i++) { - k = keys.get(i); - if (k != null && k.getEType() == target) { - if (DEBUG) { - System.out.println(pos + ": " + k); + + final int[] etypes = EType.getDefaults("default_tkt_enctypes"); + + // Sort the keys, k1 is preferred than k2 if: + // 1. k1's etype appears earlier in etypes than k2's + // 2. If same, k1's KVNO is higher + Arrays.sort(retVal, new Comparator() { + @Override + public int compare(EncryptionKey o1, EncryptionKey o2) { + if (etypes != null && etypes != EType.getBuiltInDefaults()) { + int o1EType = o1.getEType(); + int o2EType = o2.getEType(); + if (o1EType != o2EType) { + for (int i=0; i() { public Void run() { put("TerminalFactory.PC/SC", "sun.security.smartcardio.SunPCSC$Factory"); diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/sun/security/ssl/SunJSSE.java --- a/jdk/src/share/classes/sun/security/ssl/SunJSSE.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/sun/security/ssl/SunJSSE.java Wed Jul 05 16:59:43 2017 +0200 @@ -103,7 +103,7 @@ // standard constructor protected SunJSSE() { - super("SunJSSE", 1.6d, info); + super("SunJSSE", 1.7d, info); subclassCheck(); if (Boolean.TRUE.equals(fips)) { throw new ProviderException diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/classes/sun/security/util/Password.java --- a/jdk/src/share/classes/sun/security/util/Password.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/classes/sun/security/util/Password.java Wed Jul 05 16:59:43 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,14 @@ public class Password { /** Reads user password from given input stream. */ public static char[] readPassword(InputStream in) throws IOException { + return readPassword(in, false); + } + + /** Reads user password from given input stream. + * @param isEchoOn true if the password should be echoed on the screen + */ + public static char[] readPassword(InputStream in, boolean isEchoOn) + throws IOException { char[] consoleEntered = null; byte[] consoleBytes = null; @@ -44,7 +52,7 @@ try { // Use the new java.io.Console class Console con = null; - if (in == System.in && ((con = System.console()) != null)) { + if (!isEchoOn && in == System.in && ((con = System.console()) != null)) { consoleEntered = con.readPassword(); // readPassword returns "" if you just print ENTER, // to be compatible with old Password class, change to null diff -r ae9b655e7393 -r e17115919cc7 jdk/src/share/native/sun/security/ec/ec.c --- a/jdk/src/share/native/sun/security/ec/ec.c Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/share/native/sun/security/ec/ec.c Wed Jul 05 16:59:43 2017 +0200 @@ -422,7 +422,7 @@ */ if ((privKeyBytes = PORT_Alloc(2*len, kmflag)) == NULL) goto cleanup; if (randomlen != 2 * len) { - goto cleanup; + randomlen = 2 * len; } /* No need to generate - random bytes are now supplied */ /* CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(privKeyBytes, 2*len) );*/ diff -r ae9b655e7393 -r e17115919cc7 jdk/src/solaris/classes/sun/nio/ch/EPollPort.java --- a/jdk/src/solaris/classes/sun/nio/ch/EPollPort.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/solaris/classes/sun/nio/ch/EPollPort.java Wed Jul 05 16:59:43 2017 +0200 @@ -248,12 +248,13 @@ public void run() { Invoker.GroupAndInvokeCount myGroupAndInvokeCount = Invoker.getGroupAndInvokeCount(); + final boolean isPooledThread = (myGroupAndInvokeCount != null); boolean replaceMe = false; Event ev; try { for (;;) { // reset invoke count - if (myGroupAndInvokeCount != null) + if (isPooledThread) myGroupAndInvokeCount.resetInvokeCount(); try { @@ -289,7 +290,7 @@ // process event try { - ev.channel().onEvent(ev.events()); + ev.channel().onEvent(ev.events(), isPooledThread); } catch (Error x) { replaceMe = true; throw x; } catch (RuntimeException x) { diff -r ae9b655e7393 -r e17115919cc7 jdk/src/solaris/classes/sun/nio/ch/Port.java --- a/jdk/src/solaris/classes/sun/nio/ch/Port.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/solaris/classes/sun/nio/ch/Port.java Wed Jul 05 16:59:43 2017 +0200 @@ -49,7 +49,7 @@ * Implemented by clients registered with this port. */ interface PollableChannel extends Closeable { - void onEvent(int events); + void onEvent(int events, boolean mayInvokeDirect); } // maps fd to "pollable" channel @@ -121,7 +121,7 @@ final Object attachForeignChannel(final Channel channel, FileDescriptor fd) { int fdVal = IOUtil.fdVal(fd); register(fdVal, new PollableChannel() { - public void onEvent(int events) { } + public void onEvent(int events, boolean mayInvokeDirect) { } public void close() throws IOException { channel.close(); } diff -r ae9b655e7393 -r e17115919cc7 jdk/src/solaris/classes/sun/nio/ch/SolarisEventPort.java --- a/jdk/src/solaris/classes/sun/nio/ch/SolarisEventPort.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/solaris/classes/sun/nio/ch/SolarisEventPort.java Wed Jul 05 16:59:43 2017 +0200 @@ -151,12 +151,13 @@ public void run() { Invoker.GroupAndInvokeCount myGroupAndInvokeCount = Invoker.getGroupAndInvokeCount(); + final boolean isPooledThread = (myGroupAndInvokeCount != null); boolean replaceMe = false; long address = unsafe.allocateMemory(SIZEOF_PORT_EVENT); try { for (;;) { // reset invoke count - if (myGroupAndInvokeCount != null) + if (isPooledThread) myGroupAndInvokeCount.resetInvokeCount(); // wait for I/O completion event @@ -205,7 +206,7 @@ if (ch != null) { replaceMe = true; // no need to translate events - ch.onEvent(events); + ch.onEvent(events, isPooledThread); } } } finally { diff -r ae9b655e7393 -r e17115919cc7 jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java --- a/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java Wed Jul 05 16:59:43 2017 +0200 @@ -59,10 +59,13 @@ private final Object updateLock = new Object(); // pending accept - private PendingFuture pendingAccept; + private boolean acceptPending; + private CompletionHandler acceptHandler; + private Object acceptAttachment; + private PendingFuture acceptFuture; // context for permission check when security manager set - private AccessControlContext acc; + private AccessControlContext acceptAcc; UnixAsynchronousServerSocketChannelImpl(Port port) @@ -83,15 +86,6 @@ port.register(fdVal, this); } - // returns and clears the result of a pending accept - private PendingFuture grabPendingAccept() { - synchronized (updateLock) { - PendingFuture result = pendingAccept; - pendingAccept = null; - return result; - } - } - @Override void implClose() throws IOException { // remove the mapping @@ -101,17 +95,27 @@ nd.close(fd); // if there is a pending accept then complete it - final PendingFuture result = - grabPendingAccept(); - if (result != null) { - // discard the stack trace as otherwise it may appear that implClose - // has thrown the exception. - AsynchronousCloseException x = new AsynchronousCloseException(); - x.setStackTrace(new StackTraceElement[0]); - result.setFailure(x); + CompletionHandler handler; + Object att; + PendingFuture future; + synchronized (updateLock) { + if (!acceptPending) + return; // no pending accept + acceptPending = false; + handler = acceptHandler; + att = acceptAttachment; + future = acceptFuture; + } + // discard the stack trace as otherwise it may appear that implClose + // has thrown the exception. + AsynchronousCloseException x = new AsynchronousCloseException(); + x.setStackTrace(new StackTraceElement[0]); + if (handler == null) { + future.setFailure(x); + } else { // invoke by submitting task rather than directly - Invoker.invokeIndirectly(result.handler(), result); + Invoker.invokeIndirectly(this, handler, att, null, x); } } @@ -124,15 +128,17 @@ * Invoked by event handling thread when listener socket is polled */ @Override - public void onEvent(int events) { - PendingFuture result = grabPendingAccept(); - if (result == null) - return; // may have been grabbed by asynchronous close + public void onEvent(int events, boolean mayInvokeDirect) { + synchronized (updateLock) { + if (!acceptPending) + return; // may have been grabbed by asynchronous close + acceptPending = false; + } // attempt to accept connection FileDescriptor newfd = new FileDescriptor(); InetSocketAddress[] isaa = new InetSocketAddress[1]; - boolean accepted = false; + Throwable exc = null; try { begin(); int n = accept0(this.fd, newfd, isaa); @@ -140,49 +146,52 @@ // spurious wakeup, is this possible? if (n == IOStatus.UNAVAILABLE) { synchronized (updateLock) { - this.pendingAccept = result; + acceptPending = true; } port.startPoll(fdVal, Port.POLLIN); return; } - // connection accepted - accepted = true; - } catch (Throwable x) { if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); - enableAccept(); - result.setFailure(x); + exc = x; } finally { end(); } // Connection accepted so finish it when not holding locks. AsynchronousSocketChannel child = null; - if (accepted) { + if (exc == null) { try { - child = finishAccept(newfd, isaa[0], acc); - enableAccept(); - result.setResult(child); + child = finishAccept(newfd, isaa[0], acceptAcc); } catch (Throwable x) { - enableAccept(); if (!(x instanceof IOException) && !(x instanceof SecurityException)) x = new IOException(x); - result.setFailure(x); + exc = x; } } - // if an async cancel has already cancelled the operation then - // close the new channel so as to free resources - if (child != null && result.isCancelled()) { - try { - child.close(); - } catch (IOException ignore) { } + // copy field befores accept is re-renabled + CompletionHandler handler = acceptHandler; + Object att = acceptAttachment; + PendingFuture future = acceptFuture; + + // re-enable accepting and invoke handler + enableAccept(); + + if (handler == null) { + future.setResult(child, exc); + // if an async cancel has already cancelled the operation then + // close the new channel so as to free resources + if (child != null && future.isCancelled()) { + try { + child.close(); + } catch (IOException ignore) { } + } + } else { + Invoker.invoke(this, handler, att, child, exc); } - - // invoke the handler - Invoker.invoke(result.handler(), result); } /** @@ -234,16 +243,18 @@ } @Override - @SuppressWarnings("unchecked") - public Future accept(A attachment, - final CompletionHandler handler) + Future implAccept(Object att, + CompletionHandler handler) { // complete immediately if channel is closed if (!isOpen()) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invokeIndirectly(handler, result); - return result; + Throwable e = new ClosedChannelException(); + if (handler == null) { + return CompletedFuture.withFailure(e); + } else { + Invoker.invoke(this, handler, att, null, e); + return null; + } } if (localAddress == null) throw new NotYetBoundException(); @@ -258,25 +269,31 @@ throw new AcceptPendingException(); // attempt accept - AbstractFuture result = null; FileDescriptor newfd = new FileDescriptor(); InetSocketAddress[] isaa = new InetSocketAddress[1]; + Throwable exc = null; try { begin(); int n = accept0(this.fd, newfd, isaa); if (n == IOStatus.UNAVAILABLE) { - // no connection to accept - result = new PendingFuture(this, handler, attachment); // need calling context when there is security manager as // permission check may be done in a different thread without // any application call frames on the stack - synchronized (this) { - this.acc = (System.getSecurityManager() == null) ? + PendingFuture result = null; + synchronized (updateLock) { + if (handler == null) { + this.acceptHandler = null; + result = new PendingFuture(this); + this.acceptFuture = result; + } else { + this.acceptHandler = handler; + this.acceptAttachment = att; + } + this.acceptAcc = (System.getSecurityManager() == null) ? null : AccessController.getContext(); - this.pendingAccept = - (PendingFuture)result; + this.acceptPending = true; } // register for connections @@ -287,25 +304,30 @@ // accept failed if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); - result = CompletedFuture.withFailure(this, x, attachment); + exc = x; } finally { end(); } - // connection accepted immediately - if (result == null) { + AsynchronousSocketChannel child = null; + if (exc == null) { + // connection accepted immediately try { - AsynchronousSocketChannel ch = finishAccept(newfd, isaa[0], null); - result = CompletedFuture.withResult(this, ch, attachment); + child = finishAccept(newfd, isaa[0], null); } catch (Throwable x) { - result = CompletedFuture.withFailure(this, x, attachment); + exc = x; } } - // re-enable accepting and invoke handler + // re-enable accepting before invoking handler enableAccept(); - Invoker.invokeIndirectly(handler, result); - return result; + + if (handler == null) { + return CompletedFuture.withResult(child, exc); + } else { + Invoker.invokeIndirectly(this, handler, att, child, exc); + return null; + } } // -- Native methods -- diff -r ae9b655e7393 -r e17115919cc7 jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java --- a/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java Wed Jul 05 16:59:43 2017 +0200 @@ -61,20 +61,33 @@ private final Object updateLock = new Object(); // pending connect (updateLock) - private PendingFuture pendingConnect; + private boolean connectPending; + private CompletionHandler connectHandler; + private Object connectAttachment; + private PendingFuture connectFuture; - // pending remote address (statLock) + // pending remote address (stateLock) private SocketAddress pendingRemote; // pending read (updateLock) + private boolean readPending; + private boolean isScatteringRead; + private ByteBuffer readBuffer; private ByteBuffer[] readBuffers; - private boolean scatteringRead; - private PendingFuture pendingRead; + private CompletionHandler readHandler; + private Object readAttachment; + private PendingFuture readFuture; + private Future readTimer; // pending write (updateLock) + private boolean writePending; + private boolean isGatheringWrite; + private ByteBuffer writeBuffer; private ByteBuffer[] writeBuffers; - private boolean gatheringWrite; - private PendingFuture pendingWrite; + private CompletionHandler writeHandler; + private Object writeAttachment; + private PendingFuture writeFuture; + private Future writeTimer; UnixAsynchronousSocketChannelImpl(Port port) @@ -128,43 +141,36 @@ private void updateEvents() { assert Thread.holdsLock(updateLock); int events = 0; - if (pendingRead != null) + if (readPending) events |= Port.POLLIN; - if (pendingConnect != null || pendingWrite != null) + if (connectPending || writePending) events |= Port.POLLOUT; if (events != 0) port.startPoll(fdVal, events); } - /** - * Invoked by event handler thread when file descriptor is polled - */ - @Override - public void onEvent(int events) { - boolean readable = (events & Port.POLLIN) > 0; - boolean writable = (events & Port.POLLOUT) > 0; - if ((events & (Port.POLLERR | Port.POLLHUP)) > 0) { - readable = true; - writable = true; - } - - PendingFuture connectResult = null; - PendingFuture readResult = null; - PendingFuture writeResult = null; + // invoke to finish read and/or write operations + private void finish(boolean mayInvokeDirect, + boolean readable, + boolean writable) + { + boolean finishRead = false; + boolean finishWrite = false; + boolean finishConnect = false; // map event to pending result synchronized (updateLock) { - if (readable && (pendingRead != null)) { - readResult = pendingRead; - pendingRead = null; + if (readable && this.readPending) { + this.readPending = false; + finishRead = true; } if (writable) { - if (pendingWrite != null) { - writeResult = pendingWrite; - pendingWrite = null; - } else if (pendingConnect != null) { - connectResult = pendingConnect; - pendingConnect = null; + if (this.writePending) { + this.writePending = false; + finishWrite = true; + } else if (this.connectPending) { + this.connectPending = false; + finishConnect = true; } } } @@ -172,36 +178,32 @@ // complete the I/O operation. Special case for when channel is // ready for both reading and writing. In that case, submit task to // complete write if write operation has a completion handler. - if (readResult != null) { - if (writeResult != null) - finishWrite(writeResult, false); - finishRead(readResult, true); + if (finishRead) { + if (finishWrite) + finishWrite(false); + finishRead(mayInvokeDirect); return; } - if (writeResult != null) { - finishWrite(writeResult, true); + if (finishWrite) { + finishWrite(mayInvokeDirect); } - if (connectResult != null) { - finishConnect(connectResult, true); + if (finishConnect) { + finishConnect(mayInvokeDirect); } } - // returns and clears the result of a pending read - PendingFuture grabPendingRead() { - synchronized (updateLock) { - PendingFuture result = pendingRead; - pendingRead = null; - return result; + /** + * Invoked by event handler thread when file descriptor is polled + */ + @Override + public void onEvent(int events, boolean mayInvokeDirect) { + boolean readable = (events & Port.POLLIN) > 0; + boolean writable = (events & Port.POLLOUT) > 0; + if ((events & (Port.POLLERR | Port.POLLHUP)) > 0) { + readable = true; + writable = true; } - } - - // returns and clears the result of a pending write - PendingFuture grabPendingWrite() { - synchronized (updateLock) { - PendingFuture result = pendingWrite; - pendingWrite = null; - return result; - } + finish(mayInvokeDirect, readable, writable); } @Override @@ -213,26 +215,7 @@ nd.close(fd); // All outstanding I/O operations are required to fail - final PendingFuture readyToConnect; - final PendingFuture readyToRead; - final PendingFuture readyToWrite; - synchronized (updateLock) { - readyToConnect = pendingConnect; - pendingConnect = null; - readyToRead = pendingRead; - pendingRead = null; - readyToWrite = pendingWrite; - pendingWrite = null; - } - if (readyToConnect != null) { - finishConnect(readyToConnect, false); - } - if (readyToRead != null) { - finishRead(readyToRead, false); - } - if (readyToWrite != null) { - finishWrite(readyToWrite, false); - } + finish(false, true, true); } @Override @@ -240,9 +223,9 @@ if (task.getContext() == OpType.CONNECT) killConnect(); if (task.getContext() == OpType.READ) - killConnect(); + killReading(); if (task.getContext() == OpType.WRITE) - killConnect(); + killWriting(); } // -- connect -- @@ -255,15 +238,12 @@ } } - private void finishConnect(PendingFuture result, - boolean invokeDirect) - { + private void finishConnect(boolean mayInvokeDirect) { Throwable e = null; try { begin(); checkConnect(fdVal); setConnected(); - result.setResult(null); } catch (Throwable x) { if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); @@ -276,26 +256,38 @@ try { close(); } catch (IOException ignore) { } - result.setFailure(e); } - if (invokeDirect) { - Invoker.invoke(result.handler(), result); + + + // invoke handler and set result + CompletionHandler handler = connectHandler; + Object att = connectAttachment; + PendingFuture future = connectFuture; + if (handler == null) { + future.setResult(null, e); } else { - Invoker.invokeIndirectly(result.handler(), result); + if (mayInvokeDirect) { + Invoker.invokeUnchecked(handler, att, null, e); + } else { + Invoker.invokeIndirectly(this, handler, att, null, e); + } } } @Override @SuppressWarnings("unchecked") - public Future connect(SocketAddress remote, - A attachment, - CompletionHandler handler) + Future implConnect(SocketAddress remote, + A attachment, + CompletionHandler handler) { if (!isOpen()) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invoke(handler, result); - return result; + Throwable e = new ClosedChannelException(); + if (handler == null) { + return CompletedFuture.withFailure(e); + } else { + Invoker.invoke(this, handler, attachment, null, e); + return null; + } } InetSocketAddress isa = Net.checkAddress(remote); @@ -317,7 +309,6 @@ notifyBeforeTcpConnect = (localAddress == null); } - AbstractFuture result = null; Throwable e = null; try { begin(); @@ -327,15 +318,21 @@ int n = Net.connect(fd, isa.getAddress(), isa.getPort()); if (n == IOStatus.UNAVAILABLE) { // connection could not be established immediately - result = new PendingFuture(this, handler, attachment, OpType.CONNECT); + PendingFuture result = null; synchronized (updateLock) { - this.pendingConnect = (PendingFuture)result; + if (handler == null) { + result = new PendingFuture(this, OpType.CONNECT); + this.connectFuture = (PendingFuture)result; + } else { + this.connectHandler = (CompletionHandler)handler; + this.connectAttachment = attachment; + } + this.connectPending = true; updateEvents(); } return result; } setConnected(); - result = CompletedFuture.withResult(this, null, attachment); } catch (Throwable x) { if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); @@ -349,84 +346,111 @@ try { close(); } catch (IOException ignore) { } - result = CompletedFuture.withFailure(this, e, attachment); } - - Invoker.invoke(handler, result); - return result; + if (handler == null) { + return CompletedFuture.withResult(null, e); + } else { + Invoker.invoke(this, handler, attachment, null, e); + return null; + } } // -- read -- - @SuppressWarnings("unchecked") - private void finishRead(PendingFuture result, - boolean invokeDirect) - { + private void finishRead(boolean mayInvokeDirect) { int n = -1; - PendingFuture pending = null; + Throwable exc = null; + + // copy fields as we can't access them after reading is re-enabled. + boolean scattering = isScatteringRead; + CompletionHandler handler = readHandler; + Object att = readAttachment; + PendingFuture future = readFuture; + Future timeout = readTimer; + try { begin(); - ByteBuffer[] dsts = readBuffers; - if (dsts.length == 1) { - n = IOUtil.read(fd, dsts[0], -1, nd, null); + if (scattering) { + n = (int)IOUtil.read(fd, readBuffers, nd); } else { - n = (int)IOUtil.read(fd, dsts, nd); + n = IOUtil.read(fd, readBuffer, -1, nd, null); } if (n == IOStatus.UNAVAILABLE) { // spurious wakeup, is this possible? - pending = result; + synchronized (updateLock) { + readPending = true; + } return; } - // allow buffer(s) to be GC'ed. - readBuffers = null; + // allow objects to be GC'ed. + this.readBuffer = null; + this.readBuffers = null; + this.readAttachment = null; // allow another read to be initiated - boolean wasScatteringRead = scatteringRead; enableReading(); - // result is Integer or Long - if (wasScatteringRead) { - result.setResult(Long.valueOf(n)); - } else { - result.setResult(Integer.valueOf(n)); - } - } catch (Throwable x) { enableReading(); if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); - result.setFailure(x); + exc = x; } finally { // restart poll in case of concurrent write synchronized (updateLock) { - if (pending != null) - this.pendingRead = pending; updateEvents(); } end(); } - if (invokeDirect) { - Invoker.invoke(result.handler(), result); + // cancel the associated timer + if (timeout != null) + timeout.cancel(false); + + // create result + Number result = (exc != null) ? null : (scattering) ? + (Number)Long.valueOf(n) : (Number)Integer.valueOf(n); + + // invoke handler or set result + if (handler == null) { + future.setResult(result, exc); } else { - Invoker.invokeIndirectly(result.handler(), result); + if (mayInvokeDirect) { + Invoker.invokeUnchecked(handler, att, result, exc); + } else { + Invoker.invokeIndirectly(this, handler, att, result, exc); + } } } private Runnable readTimeoutTask = new Runnable() { public void run() { - PendingFuture result = grabPendingRead(); - if (result == null) - return; // already completed + CompletionHandler handler = null; + Object att = null; + PendingFuture future = null; + + synchronized (updateLock) { + if (!readPending) + return; + readPending = false; + handler = readHandler; + att = readAttachment; + future = readFuture; + } // kill further reading before releasing waiters enableReading(true); - // set completed and invoke handler - result.setFailure(new InterruptedByTimeoutException()); - Invoker.invokeIndirectly(result.handler(), result); + // invoke handler or set result + Exception exc = new InterruptedByTimeoutException(); + if (handler == null) { + future.setFailure(exc); + } else { + AsynchronousChannel ch = UnixAsynchronousSocketChannelImpl.this; + Invoker.invokeIndirectly(ch, handler, att, null, exc); + } } }; @@ -435,8 +459,9 @@ */ @Override @SuppressWarnings("unchecked") - Future readImpl(ByteBuffer[] dsts, - boolean isScatteringRead, + Future implRead(boolean isScatteringRead, + ByteBuffer dst, + ByteBuffer[] dsts, long timeout, TimeUnit unit, A attachment, @@ -450,144 +475,178 @@ boolean invokeDirect = false; boolean attemptRead = false; if (!disableSynchronousRead) { - myGroupAndInvokeCount = Invoker.getGroupAndInvokeCount(); - invokeDirect = Invoker.mayInvokeDirect(myGroupAndInvokeCount, port); - attemptRead = (handler == null) || invokeDirect || - !port.isFixedThreadPool(); // okay to attempt read with user thread pool + if (handler == null) { + attemptRead = true; + } else { + myGroupAndInvokeCount = Invoker.getGroupAndInvokeCount(); + invokeDirect = Invoker.mayInvokeDirect(myGroupAndInvokeCount, port); + // okay to attempt read with user thread pool + attemptRead = invokeDirect || !port.isFixedThreadPool(); + } } - AbstractFuture result; + int n = IOStatus.UNAVAILABLE; + Throwable exc = null; + boolean pending = false; + try { begin(); - int n; if (attemptRead) { if (isScatteringRead) { n = (int)IOUtil.read(fd, dsts, nd); } else { - n = IOUtil.read(fd, dsts[0], -1, nd, null); + n = IOUtil.read(fd, dst, -1, nd, null); } - } else { - n = IOStatus.UNAVAILABLE; } if (n == IOStatus.UNAVAILABLE) { - result = new PendingFuture(this, handler, attachment, OpType.READ); - - // update evetns so that read will complete asynchronously + PendingFuture result = null; synchronized (updateLock) { + this.isScatteringRead = isScatteringRead; + this.readBuffer = dst; this.readBuffers = dsts; - this.scatteringRead = isScatteringRead; - this.pendingRead = (PendingFuture)result; + if (handler == null) { + this.readHandler = null; + result = new PendingFuture(this, OpType.READ); + this.readFuture = (PendingFuture)result; + this.readAttachment = null; + } else { + this.readHandler = (CompletionHandler)handler; + this.readAttachment = attachment; + this.readFuture = null; + } + if (timeout > 0L) { + this.readTimer = port.schedule(readTimeoutTask, timeout, unit); + } + this.readPending = true; updateEvents(); } - - // schedule timeout - if (timeout > 0L) { - Future timeoutTask = - port.schedule(readTimeoutTask, timeout, unit); - ((PendingFuture)result).setTimeoutTask(timeoutTask); - } + pending = true; return result; } - - // data available - enableReading(); - - // result type is Long or Integer - if (isScatteringRead) { - result = (CompletedFuture)CompletedFuture - .withResult(this, Long.valueOf(n), attachment); - } else { - result = (CompletedFuture)CompletedFuture - .withResult(this, Integer.valueOf(n), attachment); - } } catch (Throwable x) { - enableReading(); if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); - result = CompletedFuture.withFailure(this, x, attachment); + exc = x; } finally { + if (!pending) + enableReading(); end(); } - if (invokeDirect) { - Invoker.invokeDirect(myGroupAndInvokeCount, handler, result); + Number result = (exc != null) ? null : (isScatteringRead) ? + (Number)Long.valueOf(n) : (Number)Integer.valueOf(n); + + // read completed immediately + if (handler != null) { + if (invokeDirect) { + Invoker.invokeDirect(myGroupAndInvokeCount, handler, attachment, (V)result, exc); + } else { + Invoker.invokeIndirectly(this, handler, attachment, (V)result, exc); + } + return null; } else { - Invoker.invokeIndirectly(handler, result); + return CompletedFuture.withResult((V)result, exc); } - return result; } // -- write -- - private void finishWrite(PendingFuture result, - boolean invokeDirect) - { - PendingFuture pending = null; + private void finishWrite(boolean mayInvokeDirect) { + int n = -1; + Throwable exc = null; + + // copy fields as we can't access them after reading is re-enabled. + boolean gathering = this.isGatheringWrite; + CompletionHandler handler = this.writeHandler; + Object att = this.writeAttachment; + PendingFuture future = this.writeFuture; + Future timer = this.writeTimer; + try { begin(); - ByteBuffer[] srcs = writeBuffers; - int n; - if (srcs.length == 1) { - n = IOUtil.write(fd, srcs[0], -1, nd, null); + if (gathering) { + n = (int)IOUtil.write(fd, writeBuffers, nd); } else { - n = (int)IOUtil.write(fd, srcs, nd); + n = IOUtil.write(fd, writeBuffer, -1, nd, null); } if (n == IOStatus.UNAVAILABLE) { // spurious wakeup, is this possible? - pending = result; + synchronized (updateLock) { + writePending = true; + } return; } - // allow buffer(s) to be GC'ed. - writeBuffers = null; + // allow objects to be GC'ed. + this.writeBuffer = null; + this.writeBuffers = null; + this.writeAttachment = null; // allow another write to be initiated - boolean wasGatheringWrite = gatheringWrite; enableWriting(); - // result is a Long or Integer - if (wasGatheringWrite) { - result.setResult(Long.valueOf(n)); - } else { - result.setResult(Integer.valueOf(n)); - } - } catch (Throwable x) { enableWriting(); if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); - result.setFailure(x); + exc = x; } finally { - // restart poll in case of concurrent read - synchronized (this) { - if (pending != null) - this.pendingWrite = pending; + // restart poll in case of concurrent write + synchronized (updateLock) { updateEvents(); } end(); } - if (invokeDirect) { - Invoker.invoke(result.handler(), result); + + // cancel the associated timer + if (timer != null) + timer.cancel(false); + + // create result + Number result = (exc != null) ? null : (gathering) ? + (Number)Long.valueOf(n) : (Number)Integer.valueOf(n); + + // invoke handler or set result + if (handler == null) { + future.setResult(result, exc); } else { - Invoker.invokeIndirectly(result.handler(), result); + if (mayInvokeDirect) { + Invoker.invokeUnchecked(handler, att, result, exc); + } else { + Invoker.invokeIndirectly(this, handler, att, result, exc); + } } } private Runnable writeTimeoutTask = new Runnable() { public void run() { - PendingFuture result = grabPendingWrite(); - if (result == null) - return; // already completed + CompletionHandler handler = null; + Object att = null; + PendingFuture future = null; + + synchronized (updateLock) { + if (!writePending) + return; + writePending = false; + handler = writeHandler; + att = writeAttachment; + future = writeFuture; + } // kill further writing before releasing waiters enableWriting(true); - // set completed and invoke handler - result.setFailure(new InterruptedByTimeoutException()); - Invoker.invokeIndirectly(result.handler(), result); + // invoke handler or set result + Exception exc = new InterruptedByTimeoutException(); + if (handler != null) { + Invoker.invokeIndirectly(UnixAsynchronousSocketChannelImpl.this, + handler, att, null, exc); + } else { + future.setFailure(exc); + } } }; @@ -596,8 +655,9 @@ */ @Override @SuppressWarnings("unchecked") - Future writeImpl(ByteBuffer[] srcs, - boolean isGatheringWrite, + Future implWrite(boolean isGatheringWrite, + ByteBuffer src, + ByteBuffer[] srcs, long timeout, TimeUnit unit, A attachment, @@ -607,66 +667,72 @@ Invoker.getGroupAndInvokeCount(); boolean invokeDirect = Invoker.mayInvokeDirect(myGroupAndInvokeCount, port); boolean attemptWrite = (handler == null) || invokeDirect || - !port.isFixedThreadPool(); // okay to attempt read with user thread pool + !port.isFixedThreadPool(); // okay to attempt write with user thread pool - AbstractFuture result; + int n = IOStatus.UNAVAILABLE; + Throwable exc = null; + boolean pending = false; + try { begin(); - int n; if (attemptWrite) { if (isGatheringWrite) { n = (int)IOUtil.write(fd, srcs, nd); } else { - n = IOUtil.write(fd, srcs[0], -1, nd, null); + n = IOUtil.write(fd, src, -1, nd, null); } - } else { - n = IOStatus.UNAVAILABLE; } if (n == IOStatus.UNAVAILABLE) { - result = new PendingFuture(this, handler, attachment, OpType.WRITE); - - // update evetns so that read will complete asynchronously + PendingFuture result = null; synchronized (updateLock) { + this.isGatheringWrite = isGatheringWrite; + this.writeBuffer = src; this.writeBuffers = srcs; - this.gatheringWrite = isGatheringWrite; - this.pendingWrite = (PendingFuture)result; + if (handler == null) { + this.writeHandler = null; + result = new PendingFuture(this, OpType.WRITE); + this.writeFuture = (PendingFuture)result; + this.writeAttachment = null; + } else { + this.writeHandler = (CompletionHandler)handler; + this.writeAttachment = attachment; + this.writeFuture = null; + } + if (timeout > 0L) { + this.writeTimer = port.schedule(writeTimeoutTask, timeout, unit); + } + this.writePending = true; updateEvents(); } - - // schedule timeout - if (timeout > 0L) { - Future timeoutTask = - port.schedule(writeTimeoutTask, timeout, unit); - ((PendingFuture)result).setTimeoutTask(timeoutTask); - } + pending = true; return result; } - - // data available - enableWriting(); - if (isGatheringWrite) { - result = (CompletedFuture)CompletedFuture - .withResult(this, Long.valueOf(n), attachment); - } else { - result = (CompletedFuture)CompletedFuture - .withResult(this, Integer.valueOf(n), attachment); - } } catch (Throwable x) { - enableWriting(); if (x instanceof ClosedChannelException) x = new AsynchronousCloseException(); - result = CompletedFuture.withFailure(this, x, attachment); + exc = x; } finally { + if (!pending) + enableWriting(); end(); } - if (invokeDirect) { - Invoker.invokeDirect(myGroupAndInvokeCount, handler, result); + + Number result = (exc != null) ? null : (isGatheringWrite) ? + (Number)Long.valueOf(n) : (Number)Integer.valueOf(n); + + // write completed immediately + if (handler != null) { + if (invokeDirect) { + Invoker.invokeDirect(myGroupAndInvokeCount, handler, attachment, (V)result, exc); + } else { + Invoker.invokeIndirectly(this, handler, attachment, (V)result, exc); + } + return null; } else { - Invoker.invokeIndirectly(handler, result); + return CompletedFuture.withResult((V)result, exc); } - return result; } // -- Native methods -- diff -r ae9b655e7393 -r e17115919cc7 jdk/src/solaris/classes/sun/nio/fs/UnixPath.java --- a/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java Wed Jul 05 16:59:43 2017 +0200 @@ -65,9 +65,6 @@ // array of offsets of elements in path (created lazily) private volatile int[] offsets; - // file permissions (created lazily) - private volatile FilePermission[] perms; - UnixPath(UnixFileSystem fs, byte[] path) { this.fs = fs; this.path = path; @@ -768,45 +765,23 @@ } } - // create file permissions used for read and write checks - private void checkReadOrWrite(boolean checkRead) { - SecurityManager sm = System.getSecurityManager(); - if (sm == null) - return; - if (perms == null) { - synchronized (this) { - if (perms == null) { - FilePermission[] p = new FilePermission[2]; - String pathForPermCheck = getPathForPermissionCheck(); - p[0] = new FilePermission(pathForPermCheck, - SecurityConstants.FILE_READ_ACTION); - p[1] = new FilePermission(pathForPermCheck, - SecurityConstants.FILE_WRITE_ACTION); - perms = p; - } - } - } - if (checkRead) { - sm.checkPermission(perms[0]); - } else { - sm.checkPermission(perms[1]); - } - } void checkRead() { - checkReadOrWrite(true); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkRead(getPathForPermissionCheck()); } void checkWrite() { - checkReadOrWrite(false); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkWrite(getPathForPermissionCheck()); } void checkDelete() { SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - // permission not cached + if (sm != null) sm.checkDelete(getPathForPermissionCheck()); - } } @Override diff -r ae9b655e7393 -r e17115919cc7 jdk/src/windows/classes/sun/nio/ch/Iocp.java --- a/jdk/src/windows/classes/sun/nio/ch/Iocp.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/windows/classes/sun/nio/ch/Iocp.java Wed Jul 05 16:59:43 2017 +0200 @@ -34,6 +34,8 @@ import java.util.concurrent.*; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.security.AccessController; +import sun.security.action.GetPropertyAction; import sun.misc.Unsafe; /** @@ -44,6 +46,7 @@ class Iocp extends AsynchronousChannelGroupImpl { private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long INVALID_HANDLE_VALUE = -1L; + private static final boolean supportsThreadAgnosticIo; // maps completion key to channel private final ReadWriteLock keyToChannelLock = new ReentrantReadWriteLock(); @@ -87,6 +90,13 @@ PendingFuture getByOverlapped(long overlapped); } + /** + * Indicates if this operating system supports thread agnostic I/O. + */ + static boolean supportsThreadAgnosticIo() { + return supportsThreadAgnosticIo; + } + // release all resources void implClose() { synchronized (this) { @@ -216,8 +226,9 @@ } while ((key == 0) || keyToChannel.containsKey(key)); // associate with I/O completion port - if (handle != 0L) + if (handle != 0L) { createIoCompletionPort(handle, port, key, 0); + } // setup mapping keyToChannel.put(key, ch); @@ -282,7 +293,7 @@ /** * Invoked if the I/O operation completes successfully. */ - public void completed(int bytesTransferred); + public void completed(int bytesTransferred, boolean canInvokeDirect); /** * Invoked if the I/O operation fails. @@ -305,6 +316,7 @@ public void run() { Invoker.GroupAndInvokeCount myGroupAndInvokeCount = Invoker.getGroupAndInvokeCount(); + boolean canInvokeDirect = (myGroupAndInvokeCount != null); CompletionStatus ioResult = new CompletionStatus(); boolean replaceMe = false; @@ -382,7 +394,7 @@ ResultHandler rh = (ResultHandler)result.getContext(); replaceMe = true; // (if error/exception then replace thread) if (error == 0) { - rh.completed(ioResult.bytesTransferred()); + rh.completed(ioResult.bytesTransferred(), canInvokeDirect); } else { rh.failed(error, translateErrorToIOException(error)); } @@ -433,5 +445,11 @@ static { Util.load(); initIDs(); + + // thread agnostic I/O on Vista/2008 or newer + String osversion = AccessController.doPrivileged( + new GetPropertyAction("os.version")); + String vers[] = osversion.split("\\."); + supportsThreadAgnosticIo = Integer.parseInt(vers[0]) >= 6; } } diff -r ae9b655e7393 -r e17115919cc7 jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java --- a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java Wed Jul 05 16:59:43 2017 +0200 @@ -146,10 +146,12 @@ // waits until all I/O operations have completed ioCache.close(); - // disassociate from port and shutdown thread pool if not default + // disassociate from port iocp.disassociate(completionKey); + + // for the non-default group close the port if (!isDefaultIocp) - iocp.shutdown(); + iocp.detachFromThreadPool(); } @Override @@ -258,14 +260,18 @@ } // invoke completion handler - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } @Override - public void completed(int bytesTransferred) { + public void completed(int bytesTransferred, boolean canInvokeDirect) { // release waiters and invoke completion handler result.setResult(fli); - Invoker.invoke(result.handler(), result); + if (canInvokeDirect) { + Invoker.invokeUnchecked(result); + } else { + Invoker.invoke(result); + } } @Override @@ -279,16 +285,16 @@ } else { result.setFailure(new AsynchronousCloseException()); } - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } } @Override - public Future lock(long position, - long size, - boolean shared, - A attachment, - CompletionHandler handler) + Future implLock(final long position, + final long size, + final boolean shared, + A attachment, + final CompletionHandler handler) { if (shared && !reading) throw new NonReadableChannelException(); @@ -298,10 +304,11 @@ // add to lock table FileLockImpl fli = addToFileLockTable(position, size, shared); if (fli == null) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invoke(handler, result); - return result; + Throwable exc = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(exc); + Invoker.invoke(this, handler, attachment, null, exc); + return null; } // create Future and task that will be invoked to acquire lock @@ -310,13 +317,20 @@ LockTask lockTask = new LockTask(position, fli, result); result.setContext(lockTask); - // initiate I/O (can only be done from thread in thread pool) - try { - Invoker.invokeOnThreadInThreadPool(this, lockTask); - } catch (ShutdownChannelGroupException e) { - // rollback - removeFromFileLockTable(fli); - throw e; + // initiate I/O + if (Iocp.supportsThreadAgnosticIo()) { + lockTask.run(); + } else { + boolean executed = false; + try { + Invoker.invokeOnThreadInThreadPool(this, lockTask); + executed = true; + } finally { + if (!executed) { + // rollback + removeFromFileLockTable(fli); + } + } } return result; } @@ -461,14 +475,14 @@ releaseBufferIfSubstituted(); // invoke completion handler - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } /** * Executed when the I/O has completed */ @Override - public void completed(int bytesTransferred) { + public void completed(int bytesTransferred, boolean canInvokeDirect) { updatePosition(bytesTransferred); // return direct buffer to cache if substituted @@ -476,14 +490,18 @@ // release waiters and invoke completion handler result.setResult(bytesTransferred); - Invoker.invoke(result.handler(), result); + if (canInvokeDirect) { + Invoker.invokeUnchecked(result); + } else { + Invoker.invoke(result); + } } @Override public void failed(int error, IOException x) { // if EOF detected asynchronously then it is reported as error if (error == ERROR_HANDLE_EOF) { - completed(-1); + completed(-1, false); } else { // return direct buffer to cache if substituted releaseBufferIfSubstituted(); @@ -494,16 +512,16 @@ } else { result.setFailure(new AsynchronousCloseException()); } - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } } } @Override - public Future read(ByteBuffer dst, - long position, - A attachment, - CompletionHandler handler) + Future implRead(ByteBuffer dst, + long position, + A attachment, + CompletionHandler handler) { if (!reading) throw new NonReadableChannelException(); @@ -514,10 +532,11 @@ // check if channel is closed if (!isOpen()) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invoke(handler, result); - return result; + Throwable exc = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(exc); + Invoker.invoke(this, handler, attachment, null, exc); + return null; } int pos = dst.position(); @@ -527,10 +546,10 @@ // no space remaining if (rem == 0) { - CompletedFuture result = - CompletedFuture.withResult(this, 0, attachment); - Invoker.invoke(handler, result); - return result; + if (handler == null) + return CompletedFuture.withResult(0); + Invoker.invoke(this, handler, attachment, 0, null); + return null; } // create Future and task that initiates read @@ -539,8 +558,12 @@ ReadTask readTask = new ReadTask(dst, pos, rem, position, result); result.setContext(readTask); - // initiate I/O (can only be done from thread in thread pool) - Invoker.invokeOnThreadInThreadPool(this, readTask); + // initiate I/O + if (Iocp.supportsThreadAgnosticIo()) { + readTask.run(); + } else { + Invoker.invokeOnThreadInThreadPool(this, readTask); + } return result; } @@ -639,14 +662,14 @@ } // invoke completion handler - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } /** * Executed when the I/O has completed */ @Override - public void completed(int bytesTransferred) { + public void completed(int bytesTransferred, boolean canInvokeDirect) { updatePosition(bytesTransferred); // return direct buffer to cache if substituted @@ -654,7 +677,11 @@ // release waiters and invoke completion handler result.setResult(bytesTransferred); - Invoker.invoke(result.handler(), result); + if (canInvokeDirect) { + Invoker.invokeUnchecked(result); + } else { + Invoker.invoke(result); + } } @Override @@ -668,15 +695,14 @@ } else { result.setFailure(new AsynchronousCloseException()); } - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } } - @Override - public Future write(ByteBuffer src, - long position, - A attachment, - CompletionHandler handler) + Future implWrite(ByteBuffer src, + long position, + A attachment, + CompletionHandler handler) { if (!writing) throw new NonWritableChannelException(); @@ -685,10 +711,11 @@ // check if channel is closed if (!isOpen()) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invoke(handler, result); - return result; + Throwable exc = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(exc); + Invoker.invoke(this, handler, attachment, null, exc); + return null; } int pos = src.position(); @@ -698,10 +725,10 @@ // nothing to write if (rem == 0) { - CompletedFuture result = - CompletedFuture.withResult(this, 0, attachment); - Invoker.invoke(handler, result); - return result; + if (handler == null) + return CompletedFuture.withResult(0); + Invoker.invoke(this, handler, attachment, 0, null); + return null; } // create Future and task to initiate write @@ -710,8 +737,12 @@ WriteTask writeTask = new WriteTask(src, pos, rem, position, result); result.setContext(writeTask); - // initiate I/O (can only be done from thread in thread pool) - Invoker.invokeOnThreadInThreadPool(this, writeTask); + // initiate I/O + if (Iocp.supportsThreadAgnosticIo()) { + writeTask.run(); + } else { + Invoker.invokeOnThreadInThreadPool(this, writeTask); + } return result; } diff -r ae9b655e7393 -r e17115919cc7 jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java --- a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java Wed Jul 05 16:59:43 2017 +0200 @@ -113,14 +113,14 @@ /** * Task to initiate accept operation and to handle result. */ - private class AcceptTask implements Runnable, Iocp.ResultHandler { + private class AcceptTask implements Runnable, Iocp.ResultHandler { private final WindowsAsynchronousSocketChannelImpl channel; private final AccessControlContext acc; - private final PendingFuture result; + private final PendingFuture result; AcceptTask(WindowsAsynchronousSocketChannelImpl channel, AccessControlContext acc, - PendingFuture result) + PendingFuture result) { this.channel = channel; this.acc = acc; @@ -222,14 +222,14 @@ } // invoke completion handler - Invoker.invokeIndirectly(result.handler(), result); + Invoker.invokeIndirectly(result); } /** * Executed when the I/O has completed */ @Override - public void completed(int bytesTransferred) { + public void completed(int bytesTransferred, boolean canInvokeDirect) { try { // connection accept after group has shutdown if (iocp.isShutdown()) { @@ -269,7 +269,7 @@ } // invoke handler (but not directly) - Invoker.invokeIndirectly(result.handler(), result); + Invoker.invokeIndirectly(result); } @Override @@ -283,19 +283,20 @@ } else { result.setFailure(new AsynchronousCloseException()); } - Invoker.invokeIndirectly(result.handler(), result); + Invoker.invokeIndirectly(result); } } @Override - public Future accept(A attachment, - final CompletionHandler handler) + Future implAccept(Object attachment, + final CompletionHandler handler) { if (!isOpen()) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invokeIndirectly(handler, result); - return result; + Throwable exc = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(exc); + Invoker.invokeIndirectly(this, handler, attachment, null, exc); + return null; } if (isAcceptKilled()) throw new RuntimeException("Accept not allowed due to cancellation"); @@ -319,10 +320,10 @@ end(); } if (ioe != null) { - CompletedFuture result = - CompletedFuture.withFailure(this, ioe, attachment); - Invoker.invokeIndirectly(handler, result); - return result; + if (handler == null) + return CompletedFuture.withFailure(ioe); + Invoker.invokeIndirectly(this, handler, attachment, null, ioe); + return null; } // need calling context when there is security manager as @@ -331,20 +332,21 @@ AccessControlContext acc = (System.getSecurityManager() == null) ? null : AccessController.getContext(); - PendingFuture result = - new PendingFuture(this, handler, attachment); - AcceptTask task = new AcceptTask(ch, acc, result); + PendingFuture result = + new PendingFuture(this, handler, attachment); + AcceptTask task = new AcceptTask(ch, acc, result); result.setContext(task); // check and set flag to prevent concurrent accepting if (!accepting.compareAndSet(false, true)) throw new AcceptPendingException(); - // initiate accept. As I/O operations are tied to the initiating thread - // then it will only be invoked direcly if this thread is in the thread - // pool. If this thread is not in the thread pool when a task is - // submitted to initiate the accept. - Invoker.invokeOnThreadInThreadPool(this, task); + // initiate I/O + if (Iocp.supportsThreadAgnosticIo()) { + task.run(); + } else { + Invoker.invokeOnThreadInThreadPool(this, task); + } return result; } diff -r ae9b655e7393 -r e17115919cc7 jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java --- a/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java Wed Jul 05 16:59:43 2017 +0200 @@ -250,14 +250,14 @@ closeChannel(); result.setFailure(toIOException(exc)); } - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } /** * Invoked by handler thread when connection established. */ @Override - public void completed(int bytesTransferred) { + public void completed(int bytesTransferred, boolean canInvokeDirect) { Throwable exc = null; try { begin(); @@ -276,7 +276,11 @@ result.setFailure(toIOException(exc)); } - Invoker.invoke(result.handler(), result); + if (canInvokeDirect) { + Invoker.invokeUnchecked(result); + } else { + Invoker.invoke(result); + } } /** @@ -290,20 +294,21 @@ } else { result.setFailure(new AsynchronousCloseException()); } - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } } @Override - public Future connect(SocketAddress remote, - A attachment, - CompletionHandler handler) + Future implConnect(SocketAddress remote, + A attachment, + CompletionHandler handler) { if (!isOpen()) { - CompletedFuture result = CompletedFuture - .withFailure(this, new ClosedChannelException(), attachment); - Invoker.invoke(handler, result); - return result; + Throwable exc = new ClosedChannelException(); + if (handler == null) + return CompletedFuture.withFailure(exc); + Invoker.invoke(this, handler, attachment, null, exc); + return null; } InetSocketAddress isa = Net.checkAddress(remote); @@ -337,10 +342,10 @@ try { close(); } catch (IOException ignore) { } - CompletedFuture result = CompletedFuture - .withFailure(this, bindException, attachment); - Invoker.invoke(handler, result); - return result; + if (handler == null) + return CompletedFuture.withFailure(bindException); + Invoker.invoke(this, handler, attachment, null, bindException); + return null; } // setup task @@ -349,8 +354,12 @@ ConnectTask task = new ConnectTask(isa, result); result.setContext(task); - // initiate I/O (can only be done from thread in thread pool) - Invoker.invokeOnThreadInThreadPool(this, task); + // initiate I/O + if (Iocp.supportsThreadAgnosticIo()) { + task.run(); + } else { + Invoker.invokeOnThreadInThreadPool(this, task); + } return result; } @@ -514,7 +523,7 @@ } // invoke completion handler - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } /** @@ -522,7 +531,7 @@ */ @Override @SuppressWarnings("unchecked") - public void completed(int bytesTransferred) { + public void completed(int bytesTransferred, boolean canInvokeDirect) { if (bytesTransferred == 0) { bytesTransferred = -1; // EOF } else { @@ -543,7 +552,11 @@ result.setResult((V)Integer.valueOf(bytesTransferred)); } } - Invoker.invoke(result.handler(), result); + if (canInvokeDirect) { + Invoker.invokeUnchecked(result); + } else { + Invoker.invoke(result); + } } @Override @@ -561,7 +574,7 @@ enableReading(); result.setFailure(x); } - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } /** @@ -579,13 +592,14 @@ } // invoke handler without any locks - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } } @Override - Future readImpl(ByteBuffer[] bufs, - boolean scatteringRead, + Future implRead(boolean isScatteringRead, + ByteBuffer dst, + ByteBuffer[] dsts, long timeout, TimeUnit unit, A attachment, @@ -594,7 +608,14 @@ // setup task PendingFuture result = new PendingFuture(this, handler, attachment); - final ReadTask readTask = new ReadTask(bufs, scatteringRead, result); + ByteBuffer[] bufs; + if (isScatteringRead) { + bufs = dsts; + } else { + bufs = new ByteBuffer[1]; + bufs[0] = dst; + } + final ReadTask readTask = new ReadTask(bufs, isScatteringRead, result); result.setContext(readTask); // schedule timeout @@ -607,8 +628,12 @@ result.setTimeoutTask(timeoutTask); } - // initiate I/O (can only be done from thread in thread pool) - Invoker.invokeOnThreadInThreadPool(this, readTask); + // initiate I/O + if (Iocp.supportsThreadAgnosticIo()) { + readTask.run(); + } else { + Invoker.invokeOnThreadInThreadPool(this, readTask); + } return result; } @@ -710,7 +735,7 @@ } @Override - @SuppressWarnings("unchecked") + //@SuppressWarnings("unchecked") public void run() { long overlapped = 0L; boolean prepared = false; @@ -759,7 +784,7 @@ } // invoke completion handler - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } /** @@ -767,7 +792,7 @@ */ @Override @SuppressWarnings("unchecked") - public void completed(int bytesTransferred) { + public void completed(int bytesTransferred, boolean canInvokeDirect) { updateBuffers(bytesTransferred); // return direct buffer to cache if substituted @@ -784,7 +809,11 @@ result.setResult((V)Integer.valueOf(bytesTransferred)); } } - Invoker.invoke(result.handler(), result); + if (canInvokeDirect) { + Invoker.invokeUnchecked(result); + } else { + Invoker.invoke(result); + } } @Override @@ -802,7 +831,7 @@ enableWriting(); result.setFailure(x); } - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } /** @@ -820,13 +849,14 @@ } // invoke handler without any locks - Invoker.invoke(result.handler(), result); + Invoker.invoke(result); } } @Override - Future writeImpl(ByteBuffer[] bufs, - boolean gatheringWrite, + Future implWrite(boolean gatheringWrite, + ByteBuffer src, + ByteBuffer[] srcs, long timeout, TimeUnit unit, A attachment, @@ -835,6 +865,13 @@ // setup task PendingFuture result = new PendingFuture(this, handler, attachment); + ByteBuffer[] bufs; + if (gatheringWrite) { + bufs = srcs; + } else { + bufs = new ByteBuffer[1]; + bufs[0] = src; + } final WriteTask writeTask = new WriteTask(bufs, gatheringWrite, result); result.setContext(writeTask); @@ -849,7 +886,12 @@ } // initiate I/O (can only be done from thread in thread pool) - Invoker.invokeOnThreadInThreadPool(this, writeTask); + // initiate I/O + if (Iocp.supportsThreadAgnosticIo()) { + writeTask.run(); + } else { + Invoker.invokeOnThreadInThreadPool(this, writeTask); + } return result; } diff -r ae9b655e7393 -r e17115919cc7 jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java --- a/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java Wed Jul 05 16:59:43 2017 +0200 @@ -46,6 +46,7 @@ @Override public WindowsFileAttributes readAttributes() throws IOException { + file.checkRead(); try { return WindowsFileAttributes.get(file, followLinks); } catch (WindowsException x) { diff -r ae9b655e7393 -r e17115919cc7 jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java --- a/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java Wed Jul 05 16:59:43 2017 +0200 @@ -246,8 +246,8 @@ long lastWriteTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTWRITETIME); long size = ((long)(unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZEHIGH)) << 32) + (unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZELOW) & 0xFFFFFFFFL); - int reparseTag = ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0) ? - + unsafe.getInt(address + OFFSETOF_FIND_DATA_RESERVED0) : 0; + int reparseTag = isReparsePoint(fileAttrs) ? + unsafe.getInt(address + OFFSETOF_FIND_DATA_RESERVED0) : 0; return new WindowsFileAttributes(fileAttrs, creationTime, lastAccessTime, @@ -275,7 +275,7 @@ int reparseTag = 0; int fileAttrs = unsafe .getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES); - if ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { + if (isReparsePoint(fileAttrs)) { int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; NativeBuffer reparseBuffer = NativeBuffers.getNativeBuffer(size); try { @@ -311,7 +311,7 @@ // just return the attributes int fileAttrs = unsafe .getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES); - if ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0) + if (!isReparsePoint(fileAttrs)) return fromFileAttributeData(address, 0); } catch (WindowsException x) { if (x.lastError() != ERROR_SHARING_VIOLATION) @@ -358,7 +358,7 @@ } /** - * Returns true if the attribtues are of the same file - both files must + * Returns true if the attributes are of the same file - both files must * be open. */ static boolean isSameFile(WindowsFileAttributes attrs1, @@ -370,6 +370,13 @@ (attrs1.fileIndexLow == attrs2.fileIndexLow); } + /** + * Returns true if the attributes are of a file with a reparse point. + */ + static boolean isReparsePoint(int attributes) { + return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; + } + // package-private int attributes() { return fileAttrs; @@ -420,7 +427,7 @@ // package private boolean isReparsePoint() { - return (fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0; + return isReparsePoint(fileAttrs); } boolean isDirectoryLink() { diff -r ae9b655e7393 -r e17115919cc7 jdk/src/windows/classes/sun/nio/fs/WindowsFileSystem.java --- a/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystem.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystem.java Wed Jul 05 16:59:43 2017 +0200 @@ -283,25 +283,15 @@ } } - // match in uppercase - StringBuilder sb = new StringBuilder(expr.length()); - for (int i=0; i= 0) { + try { + path = GetFullPathName(path); + } catch (WindowsException x) { + x.rethrowAsIOException(input); + } } // string builder to build up components of path @@ -229,12 +212,15 @@ throw new AssertionError("path type not recognized"); } - // check root directory exists - try { - FirstFile fileData = FindFirstFile(sb.toString() + "*"); - FindClose(fileData.handle()); - } catch (WindowsException x) { - x.rethrowAsIOException(path); + // if the result is only a root component then we simply check it exists + if (start >= path.length()) { + String result = sb.toString(); + try { + GetFileAttributes(result); + } catch (WindowsException x) { + x.rethrowAsIOException(path); + } + return result; } // iterate through each component to get its actual name in the @@ -246,13 +232,28 @@ String search = sb.toString() + path.substring(curr, end); try { FirstFile fileData = FindFirstFile(addLongPathPrefixIfNeeded(search)); - try { - sb.append(fileData.name()); - if (next != -1) { - sb.append('\\'); + FindClose(fileData.handle()); + + // if a reparse point is encountered then we must return the + // final path. + if (resolveLinks && + WindowsFileAttributes.isReparsePoint(fileData.attributes())) + { + String result = getFinalPath(input); + if (result == null) { + // Fallback to slow path, usually because there is a sym + // link to a file system that doesn't support sym links. + WindowsPath resolved = resolveAllLinks( + WindowsPath.createFromNormalizedPath(fs, path)); + result = getRealPath(resolved, false); } - } finally { - FindClose(fileData.handle()); + return result; + } + + // add the name to the result + sb.append(fileData.name()); + if (next != -1) { + sb.append('\\'); } } catch (WindowsException e) { e.rethrowAsIOException(path); @@ -342,7 +343,7 @@ /** * Resolve all symbolic-links in a given absolute and normalized path */ - private static String resolveAllLinks(WindowsPath path) + private static WindowsPath resolveAllLinks(WindowsPath path) throws IOException { assert path.isAbsolute(); @@ -401,7 +402,7 @@ } } - return path.toString(); + return path; } /** diff -r ae9b655e7393 -r e17115919cc7 jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java --- a/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java Wed Jul 05 16:59:43 2017 +0200 @@ -180,10 +180,12 @@ static class FirstFile { private long handle; private String name; + private int attributes; private FirstFile() { } public long handle() { return handle; } public String name() { return name; } + public int attributes() { return attributes; } } private static native void FindFirstFile0(long lpFileName, FirstFile obj) throws WindowsException; diff -r ae9b655e7393 -r e17115919cc7 jdk/src/windows/native/java/io/WinNTFileSystem_md.c --- a/jdk/src/windows/native/java/io/WinNTFileSystem_md.c Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/windows/native/java/io/WinNTFileSystem_md.c Wed Jul 05 16:59:43 2017 +0200 @@ -51,13 +51,25 @@ jfieldID path; } ids; +/** + * GetFinalPathNameByHandle is available on Windows Vista and newer + */ +typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD); +static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func; + JNIEXPORT void JNICALL Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls) { + HANDLE handle; jclass fileClass = (*env)->FindClass(env, "java/io/File"); if (!fileClass) return; ids.path = (*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;"); + handle = LoadLibrary("kernel32"); + if (handle != NULL) { + GetFinalPathNameByHandle_func = (GetFinalPathNameByHandleProc) + GetProcAddress(handle, "GetFinalPathNameByHandleW"); + } } /* -- Path operations -- */ @@ -65,6 +77,138 @@ extern int wcanonicalize(const WCHAR *path, WCHAR *out, int len); extern int wcanonicalizeWithPrefix(const WCHAR *canonicalPrefix, const WCHAR *pathWithCanonicalPrefix, WCHAR *out, int len); +/** + * Retrieves the fully resolved (final) path for the given path or NULL + * if the function fails. + */ +static WCHAR* getFinalPath(const WCHAR *path) +{ + HANDLE h; + WCHAR *result; + DWORD error; + + /* Need Windows Vista or newer to get the final path */ + if (GetFinalPathNameByHandle_func == NULL) + return NULL; + + h = CreateFileW(path, + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (h == INVALID_HANDLE_VALUE) + return NULL; + + /** + * Allocate a buffer for the resolved path. For a long path we may need + * to allocate a larger buffer. + */ + result = (WCHAR*)malloc(MAX_PATH * sizeof(WCHAR)); + if (result != NULL) { + DWORD len = (*GetFinalPathNameByHandle_func)(h, result, MAX_PATH, 0); + if (len >= MAX_PATH) { + /* retry with a buffer of the right size */ + result = (WCHAR*)realloc(result, (len+1) * sizeof(WCHAR)); + if (result != NULL) { + len = (*GetFinalPathNameByHandle_func)(h, result, len, 0); + } else { + len = 0; + } + } + if (len > 0) { + /** + * Strip prefix (should be \\?\ or \\?\UNC) + */ + if (result[0] == L'\\' && result[1] == L'\\' && + result[2] == L'?' && result[3] == L'\\') + { + int isUnc = (result[4] == L'U' && + result[5] == L'N' && + result[6] == L'C'); + int prefixLen = (isUnc) ? 7 : 4; + /* actual result length (includes terminator) */ + int resultLen = len - prefixLen + (isUnc ? 1 : 0) + 1; + + /* copy result without prefix into new buffer */ + WCHAR *tmp = (WCHAR*)malloc(resultLen * sizeof(WCHAR)); + if (tmp == NULL) { + len = 0; + } else { + WCHAR *p = result; + p += prefixLen; + if (isUnc) { + WCHAR *p2 = tmp; + p2[0] = L'\\'; + p2++; + wcscpy(p2, p); + } else { + wcscpy(tmp, p); + } + free(result); + result = tmp; + } + } + } + + /* unable to get final path */ + if (len == 0 && result != NULL) { + free(result); + result = NULL; + } + } + + error = GetLastError(); + if (CloseHandle(h)) + SetLastError(error); + return result; +} + +/** + * Retrieves file information for the specified file. If the file is + * symbolic link then the information on fully resolved target is + * returned. + */ +static BOOL getFileInformation(const WCHAR *path, + BY_HANDLE_FILE_INFORMATION *finfo) +{ + BOOL result; + DWORD error; + HANDLE h = CreateFileW(path, + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (h == INVALID_HANDLE_VALUE) + return FALSE; + result = GetFileInformationByHandle(h, finfo); + error = GetLastError(); + if (CloseHandle(h)) + SetLastError(error); + return result; +} + +/** + * If the given attributes are the attributes of a reparse point, then + * read and return the attributes of the final target. + */ +DWORD getFinalAttributesIfReparsePoint(WCHAR *path, DWORD a) +{ + if ((a != INVALID_FILE_ATTRIBUTES) && + ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0)) + { + BY_HANDLE_FILE_INFORMATION finfo; + BOOL res = getFileInformation(path, &finfo); + a = (res) ? finfo.dwFileAttributes : INVALID_FILE_ATTRIBUTES; + } + return a; +} + JNIEXPORT jstring JNICALL Java_java_io_WinNTFileSystem_canonicalize0(JNIEnv *env, jobject this, jstring pathname) @@ -202,12 +346,15 @@ return rv; if (!isReservedDeviceNameW(pathbuf)) { if (GetFileAttributesExW(pathbuf, GetFileExInfoStandard, &wfad)) { - rv = (java_io_FileSystem_BA_EXISTS - | ((wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - ? java_io_FileSystem_BA_DIRECTORY - : java_io_FileSystem_BA_REGULAR) - | ((wfad.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) - ? java_io_FileSystem_BA_HIDDEN : 0)); + DWORD a = getFinalAttributesIfReparsePoint(pathbuf, wfad.dwFileAttributes); + if (a != INVALID_FILE_ATTRIBUTES) { + rv = (java_io_FileSystem_BA_EXISTS + | ((a & FILE_ATTRIBUTE_DIRECTORY) + ? java_io_FileSystem_BA_DIRECTORY + : java_io_FileSystem_BA_REGULAR) + | ((a & FILE_ATTRIBUTE_HIDDEN) + ? java_io_FileSystem_BA_HIDDEN : 0)); + } } else { /* pagefile.sys is a special case */ if (GetLastError() == ERROR_SHARING_VIOLATION) { rv = java_io_FileSystem_BA_EXISTS; @@ -234,6 +381,7 @@ if (pathbuf == NULL) return JNI_FALSE; attr = GetFileAttributesW(pathbuf); + attr = getFinalAttributesIfReparsePoint(pathbuf, attr); free(pathbuf); if (attr == INVALID_FILE_ATTRIBUTES) return JNI_FALSE; @@ -272,6 +420,20 @@ if (pathbuf == NULL) return JNI_FALSE; a = GetFileAttributesW(pathbuf); + + /* if reparse point, get final target */ + if ((a != INVALID_FILE_ATTRIBUTES) && + ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0)) + { + WCHAR *fp = getFinalPath(pathbuf); + if (fp == NULL) { + a = INVALID_FILE_ATTRIBUTES; + } else { + free(pathbuf); + pathbuf = fp; + a = GetFileAttributesW(pathbuf); + } + } if (a != INVALID_FILE_ATTRIBUTES) { if (enable) a = a & ~FILE_ATTRIBUTE_READONLY; @@ -305,7 +467,7 @@ /* Open existing or fail */ OPEN_EXISTING, /* Backup semantics for directories */ - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, + FILE_FLAG_BACKUP_SEMANTICS, /* No template file */ NULL); if (h != INVALID_HANDLE_VALUE) { @@ -332,7 +494,16 @@ if (GetFileAttributesExW(pathbuf, GetFileExInfoStandard, &wfad)) { - rv = wfad.nFileSizeHigh * ((jlong)MAXDWORD + 1) + wfad.nFileSizeLow; + if ((wfad.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) { + rv = wfad.nFileSizeHigh * ((jlong)MAXDWORD + 1) + wfad.nFileSizeLow; + } else { + /* file is a reparse point so read attributes of final target */ + BY_HANDLE_FILE_INFORMATION finfo; + if (getFileInformation(pathbuf, &finfo)) { + rv = finfo.nFileSizeHigh * ((jlong)MAXDWORD + 1) + + finfo.nFileSizeLow; + } + } } else { if (GetLastError() == ERROR_SHARING_VIOLATION) { /* The error is "share violation", which means the file/dir @@ -360,31 +531,29 @@ if (pathbuf == NULL) return JNI_FALSE; h = CreateFileW( - pathbuf, /* Wide char path name */ - GENERIC_READ | GENERIC_WRITE, /* Read and write permission */ + pathbuf, /* Wide char path name */ + GENERIC_READ | GENERIC_WRITE, /* Read and write permission */ FILE_SHARE_READ | FILE_SHARE_WRITE, /* File sharing flags */ - NULL, /* Security attributes */ - CREATE_NEW, /* creation disposition */ - FILE_ATTRIBUTE_NORMAL, /* flags and attributes */ + NULL, /* Security attributes */ + CREATE_NEW, /* creation disposition */ + FILE_ATTRIBUTE_NORMAL | + FILE_FLAG_OPEN_REPARSE_POINT, /* flags and attributes */ NULL); if (h == INVALID_HANDLE_VALUE) { DWORD error = GetLastError(); if ((error != ERROR_FILE_EXISTS) && (error != ERROR_ALREADY_EXISTS)) { - - // If a directory by the named path already exists, - // return false (behavior of solaris and linux) instead of - // throwing an exception - DWORD fattr = GetFileAttributesW(pathbuf); - if ((fattr == INVALID_FILE_ATTRIBUTES) || - (fattr & ~FILE_ATTRIBUTE_DIRECTORY)) { + // return false rather than throwing an exception when there is + // an existing file. + DWORD a = GetFileAttributesW(pathbuf); + if (a == INVALID_FILE_ATTRIBUTES) { SetLastError(error); JNU_ThrowIOExceptionWithLastError(env, "Could not open file"); } } free(pathbuf); return JNI_FALSE; - } + } free(pathbuf); CloseHandle(h); return JNI_TRUE; @@ -396,9 +565,9 @@ /* Returns 0 on success */ DWORD a; - SetFileAttributesW(path, 0); + SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL); a = GetFileAttributesW(path); - if (a == ((DWORD)-1)) { + if (a == INVALID_FILE_ATTRIBUTES) { return 1; } else if (a & FILE_ATTRIBUTE_DIRECTORY) { return !RemoveDirectoryW(path); @@ -578,8 +747,13 @@ HANDLE h; if (pathbuf == NULL) return JNI_FALSE; - h = CreateFileW(pathbuf, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0); + h = CreateFileW(pathbuf, + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + 0); if (h != INVALID_HANDLE_VALUE) { LARGE_INTEGER modTime; FILETIME t; @@ -607,6 +781,21 @@ if (pathbuf == NULL) return JNI_FALSE; a = GetFileAttributesW(pathbuf); + + /* if reparse point, get final target */ + if ((a != INVALID_FILE_ATTRIBUTES) && + ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0)) + { + WCHAR *fp = getFinalPath(pathbuf); + if (fp == NULL) { + a = INVALID_FILE_ATTRIBUTES; + } else { + free(pathbuf); + pathbuf = fp; + a = GetFileAttributesW(pathbuf); + } + } + if (a != INVALID_FILE_ATTRIBUTES) { if (SetFileAttributesW(pathbuf, a | FILE_ATTRIBUTE_READONLY)) rv = JNI_TRUE; diff -r ae9b655e7393 -r e17115919cc7 jdk/src/windows/native/sun/nio/ch/Iocp.c --- a/jdk/src/windows/native/sun/nio/ch/Iocp.c Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/windows/native/sun/nio/ch/Iocp.c Wed Jul 05 16:59:43 2017 +0200 @@ -58,6 +58,16 @@ completionStatus_overlapped = (*env)->GetFieldID(env, clazz, "overlapped", "J"); } +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Iocp_osMajorVersion(JNIEnv* env, jclass this) +{ + OSVERSIONINFOEX ver; + ver.dwOSVersionInfoSize = sizeof(ver); + GetVersionEx((OSVERSIONINFO *) &ver); + return (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) ? + (jint)(ver.dwMajorVersion) : (jint)0; +} + JNIEXPORT jlong JNICALL Java_sun_nio_ch_Iocp_createIoCompletionPort(JNIEnv* env, jclass this, jlong handle, jlong existingPort, jint completionKey, jint concurrency) diff -r ae9b655e7393 -r e17115919cc7 jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c --- a/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c Wed Jul 05 16:59:43 2017 +0200 @@ -48,6 +48,7 @@ */ static jfieldID findFirst_handle; static jfieldID findFirst_name; +static jfieldID findFirst_attributes; static jfieldID findStream_handle; static jfieldID findStream_name; @@ -134,6 +135,7 @@ } findFirst_handle = (*env)->GetFieldID(env, clazz, "handle", "J"); findFirst_name = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;"); + findFirst_attributes = (*env)->GetFieldID(env, clazz, "attributes", "I"); clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$FirstStream"); if (clazz == NULL) { @@ -371,6 +373,7 @@ return; (*env)->SetLongField(env, obj, findFirst_handle, ptr_to_jlong(handle)); (*env)->SetObjectField(env, obj, findFirst_name, name); + (*env)->SetIntField(env, obj, findFirst_attributes, data.dwFileAttributes); } else { throwWindowsException(env, GetLastError()); } @@ -387,7 +390,7 @@ if (handle == INVALID_HANDLE_VALUE) { throwWindowsException(env, GetLastError()); } - return ptr_to_jlong(handle); + return ptr_to_jlong(handle); } JNIEXPORT jstring JNICALL diff -r ae9b655e7393 -r e17115919cc7 jdk/test/com/sun/security/auth/callback/TextCallbackHandler/Password.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/com/sun/security/auth/callback/TextCallbackHandler/Password.java Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,47 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6825240 + * @summary Password.readPassword() echos the input when System.Console is null + * @ignore run these by hand + */ + +import com.sun.security.auth.callback.TextCallbackHandler; +import javax.security.auth.callback.*; + +public class Password { + public static void main(String args[]) throws Exception { + TextCallbackHandler h = new TextCallbackHandler(); + PasswordCallback nc = new PasswordCallback("Invisible: ", false); + PasswordCallback nc2 = new PasswordCallback("Visible: ", true); + + System.out.println("Two passwords will be prompted for. The first one " + + "should have echo off, the second one on. Otherwise, this test fails"); + Callback[] callbacks = { nc, nc2 }; + h.handle(callbacks); + System.out.println("You input " + new String(nc.getPassword()) + + " and " + new String(nc2.getPassword())); + } +} diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/io/File/SymLinks.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/io/File/SymLinks.java Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,380 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 6595866 + * @summary Test java.io.File operations with sym links + */ + +import java.io.*; +import java.nio.file.Path; +import java.nio.file.attribute.*; +import static java.nio.file.LinkOption.*; + +public class SymLinks { + final static PrintStream out = System.out; + + final static File top = new File(System.getProperty("test.dir", ".")); + + // files used by the test + + final static File file = new File(top, "foofile"); + final static File link2file = new File(top, "link2file"); + final static File link2link2file = new File(top, "link2link2file"); + + final static File dir = new File(top, "foodir"); + final static File link2dir = new File(top, "link2dir"); + final static File link2link2dir = new File(top, "link2link2dir"); + + final static File link2nobody = new File(top, "link2nobody"); + final static File link2link2nobody = new File(top, "link2link2nobody"); + + /** + * Setup files, directories, and sym links used by test. + */ + static void setup() throws IOException { + // link2link2file -> link2file -> foofile + FileOutputStream fos = new FileOutputStream(file); + try { + fos.write(new byte[16*1024]); + } finally { + fos.close(); + } + mklink(link2file, file); + mklink(link2link2file, link2file); + + // link2link2dir -> link2dir -> dir + assertTrue(dir.mkdir()); + mklink(link2dir, dir); + mklink(link2link2dir, link2dir); + + // link2link2nobody -> link2nobody -> + mklink(link2nobody, new File(top, "DoesNotExist")); + mklink(link2link2nobody, link2nobody); + } + + /** + * Remove files, directories, and sym links used by test. + */ + static void cleanup() throws IOException { + if (file != null) + file.delete(); + if (link2file != null) + link2file.toPath().deleteIfExists(); + if (link2link2file != null) + link2link2file.toPath().deleteIfExists(); + if (dir != null) + dir.delete(); + if (link2dir != null) + link2dir.toPath().deleteIfExists(); + if (link2link2dir != null) + link2link2dir.toPath().deleteIfExists(); + if (link2nobody != null) + link2nobody.toPath().deleteIfExists(); + if (link2link2nobody != null) + link2link2nobody.toPath().deleteIfExists(); + } + + /** + * Creates a sym link source->target + */ + static void mklink(File source, File target) throws IOException { + source.toPath().createSymbolicLink(target.toPath()); + } + + /** + * Returns true if the "link" exists and is a sym link. + */ + static boolean isSymLink(File link) { + try { + BasicFileAttributes attrs = + Attributes.readBasicFileAttributes(link.toPath(), NOFOLLOW_LINKS); + return attrs.isSymbolicLink(); + } catch (IOException x) { + return false; + } + } + + /** + * Returns the last modified time of a sym link. + */ + static long lastModifiedOfSymLink(File link) throws IOException { + BasicFileAttributes attrs = + Attributes.readBasicFileAttributes(link.toPath(), NOFOLLOW_LINKS); + assertTrue(attrs.isSymbolicLink()); + return attrs.lastModifiedTime().toMillis(); + } + + /** + * Returns true if sym links are supported on the file system where + * "dir" exists. + */ + static boolean supportsSymLinks(File dir) { + Path link = dir.toPath().resolve("link"); + Path target = dir.toPath().resolve("target"); + try { + link.createSymbolicLink(target); + link.delete(); + return true; + } catch (UnsupportedOperationException x) { + return false; + } catch (IOException x) { + return false; + } + } + + static void assertTrue(boolean v) { + if (!v) throw new RuntimeException("Test failed"); + } + + static void assertFalse(boolean v) { + assertTrue(!v); + } + + static void header(String h) { + out.println(); + out.println(); + out.println("-- " + h + " --"); + } + + /** + * Tests go here. + */ + static void go() throws IOException { + + // check setup + assertTrue(file.isFile()); + assertTrue(isSymLink(link2file)); + assertTrue(isSymLink(link2link2file)); + assertTrue(dir.isDirectory()); + assertTrue(isSymLink(link2dir)); + assertTrue(isSymLink(link2link2dir)); + assertTrue(isSymLink(link2nobody)); + assertTrue(isSymLink(link2link2nobody)); + + header("createNewFile"); + + assertFalse(file.createNewFile()); + assertFalse(link2file.createNewFile()); + assertFalse(link2link2file.createNewFile()); + assertFalse(dir.createNewFile()); + assertFalse(link2dir.createNewFile()); + assertFalse(link2link2dir.createNewFile()); + assertFalse(link2nobody.createNewFile()); + assertFalse(link2link2nobody.createNewFile()); + + header("mkdir"); + + assertFalse(file.mkdir()); + assertFalse(link2file.mkdir()); + assertFalse(link2link2file.mkdir()); + assertFalse(dir.mkdir()); + assertFalse(link2dir.mkdir()); + assertFalse(link2link2dir.mkdir()); + assertFalse(link2nobody.mkdir()); + assertFalse(link2link2nobody.mkdir()); + + header("delete"); + + File link = new File(top, "mylink"); + try { + mklink(link, file); + assertTrue(link.delete()); + assertTrue(!isSymLink(link)); + assertTrue(file.exists()); + + mklink(link, link2file); + assertTrue(link.delete()); + assertTrue(!isSymLink(link)); + assertTrue(link2file.exists()); + + mklink(link, dir); + assertTrue(link.delete()); + assertTrue(!isSymLink(link)); + assertTrue(dir.exists()); + + mklink(link, link2dir); + assertTrue(link.delete()); + assertTrue(!isSymLink(link)); + assertTrue(link2dir.exists()); + + mklink(link, link2nobody); + assertTrue(link.delete()); + assertTrue(!isSymLink(link)); + assertTrue(isSymLink(link2nobody)); + + } finally { + link.toPath().deleteIfExists(); + } + + header("renameTo"); + + File newlink = new File(top, "newlink"); + assertTrue(link2file.renameTo(newlink)); + try { + assertTrue(file.exists()); + assertTrue(isSymLink(newlink)); + assertTrue(!isSymLink(link2file)); + } finally { + newlink.renameTo(link2file); // restore link + } + + assertTrue(link2dir.renameTo(newlink)); + try { + assertTrue(dir.exists()); + assertTrue(isSymLink(newlink)); + assertTrue(!isSymLink(link2dir)); + } finally { + newlink.renameTo(link2dir); // restore link + } + + header("list"); + + final String name = "entry"; + File entry = new File(dir, name); + try { + assertTrue(dir.list().length == 0); // directory should be empty + assertTrue(link2dir.list().length == 0); + assertTrue(link2link2dir.list().length == 0); + + assertTrue(entry.createNewFile()); + assertTrue(dir.list().length == 1); + assertTrue(dir.list()[0].equals(name)); + + // access directory by following links + assertTrue(link2dir.list().length == 1); + assertTrue(link2dir.list()[0].equals(name)); + assertTrue(link2link2dir.list().length == 1); + assertTrue(link2link2dir.list()[0].equals(name)); + + // files that are not directories + assertTrue(link2file.list() == null); + assertTrue(link2nobody.list() == null); + + } finally { + entry.delete(); + } + + header("isXXX"); + + assertTrue(file.isFile()); + assertTrue(link2file.isFile()); + assertTrue(link2link2file.isFile()); + + assertTrue(dir.isDirectory()); + assertTrue(link2dir.isDirectory()); + assertTrue(link2link2dir.isDirectory()); + + // on Windows we test with the DOS hidden attribute set + if (System.getProperty("os.name").startsWith("Windows")) { + DosFileAttributeView view = file.toPath() + .getFileAttributeView(DosFileAttributeView.class); + view.setHidden(true); + try { + assertTrue(file.isHidden()); + assertTrue(link2file.isHidden()); + assertTrue(link2link2file.isHidden()); + } finally { + view.setHidden(false); + } + assertFalse(file.isHidden()); + assertFalse(link2file.isHidden()); + assertFalse(link2link2file.isHidden()); + } + + header("length"); + + long len = file.length(); + assertTrue(len > 0L); + // these tests should follow links + assertTrue(link2file.length() == len); + assertTrue(link2link2file.length() == len); + assertTrue(link2nobody.length() == 0L); + + header("lastModified / setLastModified"); + + // need time to diff between link and file + long origLastModified = file.lastModified(); + assertTrue(origLastModified != 0L); + try { Thread.sleep(2000); } catch (InterruptedException x) { } + file.setLastModified(System.currentTimeMillis()); + + long lastModified = file.lastModified(); + assertTrue(lastModified != origLastModified); + assertTrue(lastModifiedOfSymLink(link2file) != lastModified); + assertTrue(lastModifiedOfSymLink(link2link2file) != lastModified); + assertTrue(link2file.lastModified() == lastModified); + assertTrue(link2link2file.lastModified() == lastModified); + assertTrue(link2nobody.lastModified() == 0L); + + origLastModified = dir.lastModified(); + assertTrue(origLastModified != 0L); + dir.setLastModified(0L); + assertTrue(dir.lastModified() == 0L); + assertTrue(link2dir.lastModified() == 0L); + assertTrue(link2link2dir.lastModified() == 0L); + dir.setLastModified(origLastModified); + + header("setXXX / canXXX"); + + assertTrue(file.canRead()); + assertTrue(file.canWrite()); + assertTrue(link2file.canRead()); + assertTrue(link2file.canWrite()); + assertTrue(link2link2file.canRead()); + assertTrue(link2link2file.canWrite()); + + if (file.setReadOnly()) { + assertFalse(file.canWrite()); + assertFalse(link2file.canWrite()); + assertFalse(link2link2file.canWrite()); + + assertTrue(file.setWritable(true)); // make writable + assertTrue(file.canWrite()); + assertTrue(link2file.canWrite()); + assertTrue(link2link2file.canWrite()); + + assertTrue(link2file.setReadOnly()); // make read only + assertFalse(file.canWrite()); + assertFalse(link2file.canWrite()); + assertFalse(link2link2file.canWrite()); + + assertTrue(link2link2file.setWritable(true)); // make writable + assertTrue(file.canWrite()); + assertTrue(link2file.canWrite()); + assertTrue(link2link2file.canWrite()); + } + } + + public static void main(String[] args) throws IOException { + if (supportsSymLinks(top)) { + try { + setup(); + go(); + } finally { + cleanup(); + } + } + } + +} diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/lang/String/Split.java --- a/jdk/test/java/lang/String/Split.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/test/java/lang/String/Split.java Wed Jul 05 16:59:43 2017 +0200 @@ -23,14 +23,18 @@ /** * @test + * @bug 6840246 * @summary test String.split() */ +import java.util.Arrays; +import java.util.Random; import java.util.regex.*; public class Split { public static void main(String[] args) throws Exception { String source = "0123456789"; + for (int limit=-2; limit<3; limit++) { for (int x=0; x<10; x++) { String[] result = source.split(Integer.toString(x), limit); @@ -80,5 +84,48 @@ throw new RuntimeException("String.split failure 8"); if (!result[0].equals(source)) throw new RuntimeException("String.split failure 9"); + + // check fastpath of String.split() + source = "0123456789abcdefgABCDEFG"; + Random r = new Random(); + + for (boolean doEscape: new boolean[] {false, true}) { + for (int cp = 0; cp < 0x11000; cp++) { + Pattern p = null; + String regex = new String(Character.toChars(cp)); + if (doEscape) + regex = "\\" + regex; + try { + p = Pattern.compile(regex); + } catch (PatternSyntaxException pse) { + // illegal syntax + try { + "abc".split(regex); + } catch (PatternSyntaxException pse0) { + continue; + } + throw new RuntimeException("String.split failure 11"); + } + int off = r.nextInt(source.length()); + String[] srcStrs = new String[] { + "", + source, + regex + source, + source + regex, + source.substring(0, 3) + + regex + source.substring(3, 9) + + regex + source.substring(9, 15) + + regex + source.substring(15), + source.substring(0, off) + regex + source.substring(off) + }; + for (String src: srcStrs) { + for (int limit=-2; limit<3; limit++) { + if (!Arrays.equals(src.split(regex, limit), + p.split(src, limit))) + throw new RuntimeException("String.split failure 12"); + } + } + } + } } } diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java --- a/jdk/test/java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java Wed Jul 05 16:59:43 2017 +0200 @@ -22,7 +22,7 @@ */ /* @test - * @bug 4607272 + * @bug 4607272 6842687 * @summary Unit test for AsynchronousChannelGroup */ @@ -50,8 +50,6 @@ } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort(); @@ -97,9 +95,6 @@ System.out.println("Read failed (expected)"); latch.countDown(); } - public void cancelled(Void att) { - throw new RuntimeException(); - } }); // close channel or shutdown group @@ -122,9 +117,6 @@ public void failed(Throwable exc, Void att) { throw new RuntimeException(exc); } - public void cancelled(Void att) { - throw new RuntimeException(); - } }); latch.await(); diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/nio/channels/AsynchronousChannelGroup/Identity.java --- a/jdk/test/java/nio/channels/AsynchronousChannelGroup/Identity.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Identity.java Wed Jul 05 16:59:43 2017 +0200 @@ -22,7 +22,7 @@ */ /* @test - * @bug 4607272 + * @bug 4607272 6842687 * @summary Unit test for AsynchronousChannelGroup */ @@ -90,14 +90,10 @@ } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort(); SocketAddress sa = new InetSocketAddress(InetAddress.getLocalHost(), port); @@ -141,9 +137,6 @@ public void failed(Throwable exc, Integer groupId) { fail(exc.getMessage()); } - public void cancelled(Integer groupId) { - fail("I/O operation was cancelled"); - } }); // wait until diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/nio/channels/AsynchronousChannelGroup/Restart.java --- a/jdk/test/java/nio/channels/AsynchronousChannelGroup/Restart.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Restart.java Wed Jul 05 16:59:43 2017 +0200 @@ -22,7 +22,7 @@ */ /* @test - * @bug 4607272 + * @bug 4607272 6842687 * @summary Unit test for AsynchronousChannelGroup * @build Restart * @run main/othervm -XX:-UseVMInterruptibleIO Restart @@ -111,8 +111,6 @@ } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); // establish loopback connection which should cause completion diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java --- a/jdk/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java Wed Jul 05 16:59:43 2017 +0200 @@ -22,7 +22,7 @@ */ /* @test - * @bug 4607272 + * @bug 4607272 6842687 * @summary Unit test for AsynchronousChannelGroup */ @@ -52,8 +52,6 @@ } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); System.out.println("Listener created."); @@ -97,8 +95,6 @@ } public void failed(Throwable exc, AsynchronousSocketChannel ch) { } - public void cancelled(AsynchronousSocketChannel ch) { - } }); } System.out.println("All read operations outstanding."); diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/nio/channels/AsynchronousDatagramChannel/Basic.java --- a/jdk/test/java/nio/channels/AsynchronousDatagramChannel/Basic.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/test/java/nio/channels/AsynchronousDatagramChannel/Basic.java Wed Jul 05 16:59:43 2017 +0200 @@ -22,7 +22,7 @@ */ /* @test - * @bug 4527345 + * @bug 4527345 6842687 * @summary Unit test for AsynchronousDatagramChannel */ @@ -72,8 +72,6 @@ } public void failed (Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); Thread.sleep(2000); sender.send(ByteBuffer.wrap(msg), sa); @@ -88,8 +86,6 @@ public void failed (Throwable exc, Void att) { exception.set(exc); } - public void cancelled(Void att) { - } }); Throwable result; while ((result = exception.get()) == null) { @@ -107,8 +103,6 @@ public void failed (Throwable exc, Void att) { exception.set(exc); } - public void cancelled(Void att) { - } }); ch.close(); while ((result = exception.get()) == null) { @@ -162,8 +156,6 @@ } public void failed (Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); Thread.sleep(2000); sender.send(ByteBuffer.wrap(msg), sa); @@ -178,8 +170,6 @@ public void failed (Throwable exc, Void att) { exception.set(exc); } - public void cancelled(Void att) { - } }); Throwable result; while ((result = exception.get()) == null) { @@ -197,8 +187,6 @@ public void failed (Throwable exc, Void att) { exception.set(exc); } - public void cancelled(Void att) { - } }); ch.close(); while ((result = exception.get()) == null) { @@ -246,8 +234,6 @@ } public void failed (Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); l2.await(5, TimeUnit.SECONDS); @@ -272,8 +258,6 @@ throw new RuntimeException(exc); } } - public void cancelled(Void att) { - } }); l3.await(5, TimeUnit.SECONDS); @@ -323,8 +307,6 @@ } public void failed (Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); l2.await(5, TimeUnit.SECONDS); @@ -340,7 +322,7 @@ reader.close(); } - static void cancelAndCheck(Future result, CountDownLatch latch) + static void cancelAndCheck(Future result) throws InterruptedException { boolean cancelled = result.cancel(false); @@ -356,37 +338,22 @@ } catch (ExecutionException e) { throw new RuntimeException("Should not fail"); } - - // make sure that completion handler is invoked - latch.await(); } // basic cancel tests static void doCancelTests() throws Exception { InetAddress lh = InetAddress.getLocalHost(); - // timed and non-timed receive + // receive for (int i=0; i<2; i++) { AsynchronousDatagramChannel ch = AsynchronousDatagramChannel.open().bind(new InetSocketAddress(0)); - final CountDownLatch latch = new CountDownLatch(1); - long timeout = (i == 0) ? 0L : 60L; - Future remote = ch - .receive(ByteBuffer.allocate(100), timeout, TimeUnit.SECONDS, (Void)null, - new CompletionHandler() { - public void completed(SocketAddress source, Void att) { - } - public void failed (Throwable exc, Void att) { - } - public void cancelled(Void att) { - latch.countDown(); - } - }); - cancelAndCheck(remote, latch); + Future remote = ch.receive(ByteBuffer.allocate(100)); + cancelAndCheck(remote); ch.close(); } - // timed and non-timed read + // read for (int i=0; i<2; i++) { AsynchronousDatagramChannel ch = AsynchronousDatagramChannel.open().bind(new InetSocketAddress(0)); @@ -394,18 +361,8 @@ ((InetSocketAddress)(ch.getLocalAddress())).getPort())); final CountDownLatch latch = new CountDownLatch(1); long timeout = (i == 0) ? 0L : 60L; - Future result = ch - .read(ByteBuffer.allocate(100), timeout, TimeUnit.SECONDS, (Void)null, - new CompletionHandler() { - public void completed(Integer bytesRead, Void att) { - } - public void failed (Throwable exc, Void att) { - } - public void cancelled(Void att) { - latch.countDown(); - } - }); - cancelAndCheck(result, latch); + Future result = ch.read(ByteBuffer.allocate(100)); + cancelAndCheck(result); ch.close(); } } diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/nio/channels/AsynchronousFileChannel/Basic.java --- a/jdk/test/java/nio/channels/AsynchronousFileChannel/Basic.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/Basic.java Wed Jul 05 16:59:43 2017 +0200 @@ -22,7 +22,7 @@ */ /* @test - * @bug 4607272 6822643 6830721 + * @bug 4607272 6822643 6830721 6842687 * @summary Unit test for AsynchronousFileChannel */ @@ -195,8 +195,6 @@ } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); throw new RuntimeException("OverlappingFileLockException expected"); } catch (OverlappingFileLockException x) { @@ -229,8 +227,6 @@ } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); // wait for handler to complete @@ -318,8 +314,6 @@ } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); await(latch); @@ -338,8 +332,41 @@ } } finally { ch.close(); + executor.shutdown(); } } + + + // test sharing a thread pool between many channels + ExecutorService executor = Executors + .newFixedThreadPool(1+rand.nextInt(10), threadFactory); + final int n = 50 + rand.nextInt(50); + AsynchronousFileChannel[] channels = new AsynchronousFileChannel[n]; + try { + for (int i=0; i opts = EnumSet.of(WRITE); + channels[i] = AsynchronousFileChannel.open(file, opts, executor); + final CountDownLatch latch = new CountDownLatch(1); + channels[i].write(genBuffer(), 0L, (Void)null, new CompletionHandler() { + public void completed(Integer result, Void att) { + latch.countDown(); + } + public void failed(Throwable exc, Void att) { + } + }); + await(latch); + + // close ~half the channels + if (rand.nextBoolean()) + channels[i].close(); + } + } finally { + // close remaining channels + for (int i=0; i res = ch.write(genBuffer(), 0L, (Void)null, - new CompletionHandler() { - public void completed(Integer result, Void att) { - } - public void failed(Throwable exc, Void att) { - } - public void cancelled(Void att) { - latch.countDown(); - } - }); + Future res = ch.write(genBuffer(), 0L); // cancel operation boolean cancelled = res.cancel(mayInterruptIfRunning); @@ -456,10 +473,6 @@ throw new RuntimeException(x); } - // check that cancelled method is invoked - if (cancelled) - await(latch); - ch.close(); } } @@ -547,8 +560,6 @@ } public void failed(Throwable exc, Long position) { } - public void cancelled(Long position) { - } }); // wait for writes to complete @@ -574,8 +585,6 @@ } public void failed(Throwable exc, Long position) { } - public void cancelled(Long position) { - } }); // wait for reads to complete diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/nio/channels/AsynchronousFileChannel/CustomThreadPool.java --- a/jdk/test/java/nio/channels/AsynchronousFileChannel/CustomThreadPool.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/CustomThreadPool.java Wed Jul 05 16:59:43 2017 +0200 @@ -22,7 +22,7 @@ */ /* @test - * @bug 4607272 + * @bug 4607272 6842687 * @summary Unit test for java.nio.channels.AsynchronousFileChannel * @build CustomThreadPool MyThreadFactory * @run main/othervm -Djava.nio.channels.DefaultThreadPool.threadFactory=MyThreadFactory CustomThreadPool @@ -51,8 +51,6 @@ } public void failed(Throwable exc, AtomicReference invoker) { } - public void cancelled(AtomicReference invoker) { - } }); Thread t; while ((t = invoker.get()) == null) { diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/nio/channels/AsynchronousFileChannel/Lock.java --- a/jdk/test/java/nio/channels/AsynchronousFileChannel/Lock.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/Lock.java Wed Jul 05 16:59:43 2017 +0200 @@ -23,7 +23,7 @@ /* @test - * @bug 4607272 6814948 + * @bug 4607272 6814948 6842687 * @summary Unit test for AsynchronousFileChannel#lock method */ @@ -97,7 +97,7 @@ slave.lock(0, 10, false); // this VM acquires lock on non-overlapping range - fl = ch.lock(10, 10, false, null, null).get(); + fl = ch.lock(10, 10, false).get(); fl.release(); // done diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java --- a/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java Wed Jul 05 16:59:43 2017 +0200 @@ -22,7 +22,7 @@ */ /* @test - * @bug 4607272 + * @bug 4607272 6842687 * @summary Unit test for AsynchronousServerSocketChannel * @run main/timeout=180 Basic */ @@ -104,8 +104,6 @@ public void failed(Throwable exc, Void att) { exception.set(exc); } - public void cancelled(Void att) { - } }); // check AcceptPendingException diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java --- a/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java Wed Jul 05 16:59:43 2017 +0200 @@ -22,7 +22,7 @@ */ /* @test - * @bug 4607272 + * @bug 4607272 6842687 * @summary Unit test for AsynchronousSocketChannel * @run main/timeout=600 Basic */ @@ -187,8 +187,6 @@ public void failed(Throwable exc, Void att) { connectException.set(exc); } - public void cancelled(Void att) { - } }); while (connectException.get() == null) { Thread.sleep(100); @@ -289,8 +287,6 @@ public void failed(Throwable x, AsynchronousSocketChannel ch) { writeException.set(x); } - public void cancelled(AsynchronousSocketChannel ch) { - } }); // give time for socket buffer to fill up. @@ -330,18 +326,8 @@ SocketChannel peer = server.accept(); // start read operation - final CountDownLatch latch = new CountDownLatch(1); ByteBuffer buf = ByteBuffer.allocate(1); - Future res = ch.read(buf, (Void)null, - new CompletionHandler() { - public void completed(Integer result, Void att) { - } - public void failed(Throwable exc, Void att) { - } - public void cancelled(Void att) { - latch.countDown(); - } - }); + Future res = ch.read(buf); // cancel operation boolean cancelled = res.cancel(mayInterruptIfRunning); @@ -362,8 +348,11 @@ } catch (CancellationException x) { } - // check that completion handler executed. - latch.await(); + // check that the cancel doesn't impact writing to the channel + if (!mayInterruptIfRunning) { + buf = ByteBuffer.wrap("a".getBytes()); + ch.write(buf).get(); + } ch.close(); peer.close(); @@ -408,8 +397,6 @@ } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); latch.await(); @@ -460,8 +447,6 @@ } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); // trickle the writing @@ -507,26 +492,24 @@ } // scattering read that completes ascynhronously - final CountDownLatch latch = new CountDownLatch(1); + final CountDownLatch l1 = new CountDownLatch(1); ch.read(dsts, 0, dsts.length, 0L, TimeUnit.SECONDS, (Void)null, new CompletionHandler() { public void completed(Long result, Void att) { long n = result; if (n <= 0) throw new RuntimeException("No bytes read"); - latch.countDown(); + l1.countDown(); } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); // write some bytes sc.write(genBuffer()); // read should now complete - latch.await(); + l1.await(); // write more bytes sc.write(genBuffer()); @@ -535,10 +518,20 @@ for (int i=0; i() { + public void completed(Long result, Void att) { + long n = result; + if (n <= 0) + throw new RuntimeException("No bytes read"); + l2.countDown(); + } + public void failed(Throwable exc, Void att) { + } + }); + l2.await(); ch.close(); sc.close(); @@ -574,8 +567,6 @@ } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); // read to EOF or buffer full @@ -613,19 +604,29 @@ ch.connect(server.address()).get(); SocketChannel sc = server.accept(); + // number of bytes written + final AtomicLong bytesWritten = new AtomicLong(0); + // write buffers (should complete immediately) ByteBuffer[] srcs = genBuffers(1); - long n = ch - .write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS, (Void)null, null).get(); - if (n <= 0) - throw new RuntimeException("No bytes written"); + final CountDownLatch l1 = new CountDownLatch(1); + ch.write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS, (Void)null, + new CompletionHandler() { + public void completed(Long result, Void att) { + long n = result; + if (n <= 0) + throw new RuntimeException("No bytes read"); + bytesWritten.addAndGet(n); + l1.countDown(); + } + public void failed(Throwable exc, Void att) { + } + }); + l1.await(); // set to true to signal that no more buffers should be written final AtomicBoolean continueWriting = new AtomicBoolean(true); - // number of bytes written - final AtomicLong bytesWritten = new AtomicLong(n); - // write until socket buffer is full so as to create the conditions // for when a write does not complete immediately srcs = genBuffers(1); @@ -644,8 +645,6 @@ } public void failed(Throwable exc, Void att) { } - public void cancelled(Void att) { - } }); // give time for socket buffer to fill up. @@ -658,7 +657,7 @@ ByteBuffer buf = ByteBuffer.allocateDirect(4096); long total = 0L; do { - n = sc.read(buf); + int n = sc.read(buf); if (n <= 0) throw new RuntimeException("No bytes read"); buf.rewind(); @@ -714,15 +713,27 @@ System.out.println("-- timeout when reading --"); + ByteBuffer dst = ByteBuffer.allocate(512); + + final AtomicReference readException = new AtomicReference(); + // this read should timeout - ByteBuffer dst = ByteBuffer.allocate(512); - try { - ch.read(dst, 3, TimeUnit.SECONDS, (Void)null, null).get(); - throw new RuntimeException("Read did not timeout"); - } catch (ExecutionException x) { - if (!(x.getCause() instanceof InterruptedByTimeoutException)) - throw new RuntimeException("InterruptedByTimeoutException expected"); + ch.read(dst, 3, TimeUnit.SECONDS, (Void)null, + new CompletionHandler() + { + public void completed(Integer result, Void att) { + throw new RuntimeException("Should not complete"); + } + public void failed(Throwable exc, Void att) { + readException.set(exc); + } + }); + // wait for exception + while (readException.get() == null) { + Thread.sleep(100); } + if (!(readException.get() instanceof InterruptedByTimeoutException)) + throw new RuntimeException("InterruptedByTimeoutException expected"); // after a timeout then further reading should throw unspecified runtime exception boolean exceptionThrown = false; @@ -752,8 +763,6 @@ public void failed(Throwable exc, AsynchronousSocketChannel ch) { writeException.set(exc); } - public void cancelled(AsynchronousSocketChannel ch) { - } }); // wait for exception diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/nio/channels/AsynchronousSocketChannel/DieBeforeComplete.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousSocketChannel/DieBeforeComplete.java Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,136 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 6842687 + * @summary Unit test for AsynchronousSocketChannel/AsynchronousServerSocketChannel + */ +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.net.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Initiates I/O operation on a thread that terminates before the I/O completes. + */ + +public class DieBeforeComplete { + + public static void main(String[] args) throws Exception { + final AsynchronousServerSocketChannel listener = + AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(0)); + + InetAddress lh = InetAddress.getLocalHost(); + int port = ((InetSocketAddress) (listener.getLocalAddress())).getPort(); + final SocketAddress sa = new InetSocketAddress(lh, port); + + // -- accept -- + + // initiate accept in a thread that dies before connection is established + Future r1 = + initiateAndDie(new Task() { + public Future run() { + return listener.accept(); + }}); + + // establish and accept connection + SocketChannel peer = SocketChannel.open(sa); + final AsynchronousSocketChannel channel = r1.get(); + + // --- read -- + + // initiate read in a thread that dies befores bytes are available + final ByteBuffer dst = ByteBuffer.allocate(100); + Future r2 = initiateAndDie(new Task() { + public Future run() { + return channel.read(dst); + }}); + + // send bytes + peer.write(ByteBuffer.wrap("hello".getBytes())); + int nread = r2.get(); + if (nread <= 0) + throw new RuntimeException("Should have read at least one byte"); + + // -- write -- + + // initiate writes in threads that dies + boolean completedImmediately; + Future r3; + do { + final ByteBuffer src = ByteBuffer.wrap(new byte[10000]); + r3 = initiateAndDie(new Task() { + public Future run() { + return channel.write(src); + }}); + try { + int nsent = r3.get(5, TimeUnit.SECONDS); + if (nsent <= 0) + throw new RuntimeException("Should have wrote at least one byte"); + completedImmediately = true; + } catch (TimeoutException x) { + completedImmediately = false; + } + } while (completedImmediately); + + // drain connection + peer.configureBlocking(false); + ByteBuffer src = ByteBuffer.allocateDirect(10000); + do { + src.clear(); + nread = peer.read(src); + if (nread == 0) { + Thread.sleep(100); + nread = peer.read(src); + } + } while (nread > 0); + + // write should complete now + int nsent = r3.get(); + if (nsent <= 0) + throw new RuntimeException("Should have wrote at least one byte"); + } + + static interface Task { + Future run(); + } + + static Future initiateAndDie(final Task task) { + final AtomicReference> result = new AtomicReference>(); + Runnable r = new Runnable() { + public void run() { + result.set(task.run()); + } + }; + Thread t = new Thread(r); + t.start(); + while (t.isAlive()) { + try { + t.join(); + } catch (InterruptedException x) { + } + } + return result.get(); + } +} diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java --- a/jdk/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java Wed Jul 05 16:59:43 2017 +0200 @@ -22,7 +22,7 @@ */ /* @test - * @bug 6834246 + * @bug 6834246 6842687 * @summary Stress test connections through the loopback interface */ @@ -114,8 +114,6 @@ exc.printStackTrace(); closeUnchecked(channel); } - public void cancelled(Void att) { - } }); } @@ -156,8 +154,6 @@ exc.printStackTrace(); closeUnchecked(channel); } - public void cancelled(Void att) { - } }); } diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/nio/channels/FileChannel/ReleaseOnCloseDeadlock.java --- a/jdk/test/java/nio/channels/FileChannel/ReleaseOnCloseDeadlock.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/test/java/nio/channels/FileChannel/ReleaseOnCloseDeadlock.java Wed Jul 05 16:59:43 2017 +0200 @@ -22,7 +22,7 @@ */ /* @test - * @bug 6543863 + * @bug 6543863 6842687 * @summary Try to cause a deadlock between (Asynchronous)FileChannel.close * and FileLock.release */ @@ -56,7 +56,7 @@ AsynchronousFileChannel ch = AsynchronousFileChannel.open(file, READ, WRITE); for (int i=0; i permissionsChecked = new ArrayList(); + private Set propertiesChecked = new HashSet(); + private List readsChecked = new ArrayList(); + private List writesChecked = new ArrayList(); + private List deletesChecked = new ArrayList(); + private List execsChecked = new ArrayList(); + + List permissionsChecked() { return permissionsChecked; } + Set propertiesChecked() { return propertiesChecked; } + List readsChecked() { return readsChecked; } + List writesChecked() { return writesChecked; } + List deletesChecked() { return deletesChecked; } + List execsChecked() { return execsChecked; } + } + + static ThreadLocal myChecks = + new ThreadLocal() { + @Override protected Checks initialValue() { + return null; + } + }; + + static void prepare() { + myChecks.set(new Checks()); + } + + static void assertCheckPermission(Class type, + String name) + { + for (Permission perm: myChecks.get().permissionsChecked()) { + if (type.isInstance(perm) && perm.getName().equals(name)) + return; + } + throw new RuntimeException(type.getName() + "\"" + name + "\") not checked"); + } + + static void assertCheckPropertyAccess(String key) { + if (!myChecks.get().propertiesChecked().contains(key)) + throw new RuntimeException("Property " + key + " not checked"); + } + + static void assertChecked(Path file, List list) { + String s = file.toString(); + for (String f: list) { + if (f.endsWith(s)) + return; + } + throw new RuntimeException("Access not checked"); + } + + static void assertCheckRead(Path file) { + assertChecked(file, myChecks.get().readsChecked()); + } + + static void assertCheckWrite(Path file) { + assertChecked(file, myChecks.get().writesChecked()); + } + + static void assertCheckDelete(Path file) { + assertChecked(file, myChecks.get().deletesChecked()); + } + + static void assertCheckExec(Path file) { + assertChecked(file, myChecks.get().execsChecked()); + } + + static class LoggingSecurityManager extends SecurityManager { + static void install() { + System.setSecurityManager(new LoggingSecurityManager()); + } + + @Override + public void checkPermission(Permission perm) { + Checks checks = myChecks.get(); + if (checks != null) + checks.permissionsChecked().add(perm); + } + + @Override + public void checkPropertyAccess(String key) { + Checks checks = myChecks.get(); + if (checks != null) + checks.propertiesChecked().add(key); + } + + @Override + public void checkRead(String file) { + Checks checks = myChecks.get(); + if (checks != null) + checks.readsChecked().add(file); + } + + @Override + public void checkWrite(String file) { + Checks checks = myChecks.get(); + if (checks != null) + checks.writesChecked().add(file); + } + + @Override + public void checkDelete(String file) { + Checks checks = myChecks.get(); + if (checks != null) + checks.deletesChecked().add(file); + } + + @Override + public void checkExec(String file) { + Checks checks = myChecks.get(); + if (checks != null) + checks.execsChecked().add(file); + } + } + + static void testBasicFileAttributeView(BasicFileAttributeView view, Path file) + throws IOException + { + prepare(); + view.readAttributes(); + assertCheckRead(file); + + prepare(); + FileTime now = FileTime.fromMillis(System.currentTimeMillis()); + view.setTimes(null, now, now); + assertCheckWrite(file); + } + + static void testPosixFileAttributeView(PosixFileAttributeView view, Path file) + throws IOException + { + prepare(); + PosixFileAttributes attrs = view.readAttributes(); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + + prepare(); + view.setPermissions(attrs.permissions()); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + + prepare(); + view.setOwner(attrs.owner()); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + + prepare(); + view.setOwner(attrs.owner()); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + } + + public static void main(String[] args) throws IOException { + Path dir = Paths.get(System.getProperty("test.src", ".")); + Path file = dir.resolve("file1234").createFile(); + try { + LoggingSecurityManager.install(); + + // -- checkAccess -- + + prepare(); + file.checkAccess(); + assertCheckRead(file); + + prepare(); + file.checkAccess(AccessMode.READ); + assertCheckRead(file); + + prepare(); + file.checkAccess(AccessMode.WRITE); + assertCheckWrite(file); + + prepare(); + try { + file.checkAccess(AccessMode.EXECUTE); + } catch (AccessDeniedException x) { } + assertCheckExec(file); + + prepare(); + try { + file.checkAccess(AccessMode.READ, AccessMode.WRITE, AccessMode.EXECUTE); + } catch (AccessDeniedException x) { } + assertCheckRead(file); + assertCheckWrite(file); + assertCheckExec(file); + + // -- copyTo -- + + Path target = dir.resolve("target1234"); + prepare(); + file.copyTo(target); + try { + assertCheckRead(file); + assertCheckWrite(target); + } finally { + target.delete(); + } + + if (TestUtil.supportsLinks(dir)) { + Path link = dir.resolve("link1234").createSymbolicLink(file); + try { + prepare(); + link.copyTo(target, LinkOption.NOFOLLOW_LINKS); + try { + assertCheckRead(link); + assertCheckWrite(target); + assertCheckPermission(LinkPermission.class, "symbolic"); + } finally { + target.delete(); + } + } finally { + link.delete(); + } + } + + // -- createDirectory -- + + Path subdir = dir.resolve("subdir1234"); + prepare(); + subdir.createDirectory(); + try { + assertCheckWrite(subdir); + } finally { + subdir.delete(); + } + + // -- createFile -- + + Path fileToCreate = dir.resolve("file7890"); + prepare(); + try { + fileToCreate.createFile(); + assertCheckWrite(fileToCreate); + } finally { + fileToCreate.delete(); + } + + // -- createSymbolicLink -- + + if (TestUtil.supportsLinks(dir)) { + prepare(); + Path link = dir.resolve("link1234").createSymbolicLink(file); + try { + assertCheckWrite(link); + assertCheckPermission(LinkPermission.class, "symbolic"); + } finally { + link.delete(); + } + } + + // -- delete/deleteIfExists -- + + Path fileToDelete = dir.resolve("file7890"); + + fileToDelete.createFile(); + prepare(); + fileToDelete.delete(); + assertCheckDelete(fileToDelete); + + fileToDelete.createFile(); + prepare(); + fileToDelete.deleteIfExists(); + assertCheckDelete(fileToDelete); + + // -- exists/notExists -- + + prepare(); + file.exists(); + assertCheckRead(file); + + prepare(); + file.notExists(); + assertCheckRead(file); + + // -- getFileStore -- + + prepare(); + file.getFileStore(); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, "getFileStoreAttributes"); + + // -- isSameFile -- + + prepare(); + file.isSameFile(dir); + assertCheckRead(file); + assertCheckRead(dir); + + // -- moveTo -- + + Path target2 = dir.resolve("target1234"); + prepare(); + file.moveTo(target2); + try { + assertCheckWrite(file); + assertCheckWrite(target2); + } finally { + // restore file + target2.moveTo(file); + } + + // -- newByteChannel -- + + SeekableByteChannel sbc; + + prepare(); + sbc = file.newByteChannel(); + try { + assertCheckRead(file); + } finally { + sbc.close(); + } + prepare(); + sbc = file.newByteChannel(StandardOpenOption.WRITE); + try { + assertCheckWrite(file); + } finally { + sbc.close(); + } + prepare(); + sbc = file.newByteChannel(StandardOpenOption.READ, StandardOpenOption.WRITE); + try { + assertCheckRead(file); + assertCheckWrite(file); + } finally { + sbc.close(); + } + + prepare(); + sbc = file.newByteChannel(StandardOpenOption.DELETE_ON_CLOSE); + try { + assertCheckRead(file); + assertCheckDelete(file); + } finally { + sbc.close(); + } + file.createFile(); // restore file + + + // -- newInputStream/newOutptuStream -- + + prepare(); + InputStream in = file.newInputStream(); + try { + assertCheckRead(file); + } finally { + in.close(); + } + prepare(); + OutputStream out = file.newOutputStream(); + try { + assertCheckWrite(file); + } finally { + out.close(); + } + + // -- newDirectoryStream -- + + prepare(); + DirectoryStream stream = dir.newDirectoryStream(); + try { + assertCheckRead(dir); + + if (stream instanceof SecureDirectoryStream) { + Path entry; + SecureDirectoryStream sds = + (SecureDirectoryStream)stream; + + // newByteChannel + entry = file.getName(); + prepare(); + sbc = sds.newByteChannel(entry, EnumSet.of(StandardOpenOption.READ)); + try { + assertCheckRead(file); + } finally { + sbc.close(); + } + prepare(); + sbc = sds.newByteChannel(entry, EnumSet.of(StandardOpenOption.WRITE)); + try { + assertCheckWrite(file); + } finally { + sbc.close(); + } + + // deleteFile + entry = file.getName(); + prepare(); + sds.deleteFile(entry); + assertCheckDelete(file); + dir.resolve(entry).createFile(); // restore file + + // deleteDirectory + entry = Paths.get("subdir1234"); + dir.resolve(entry).createDirectory(); + prepare(); + sds.deleteDirectory(entry); + assertCheckDelete(dir.resolve(entry)); + + // move + entry = Paths.get("tempname1234"); + prepare(); + sds.move(file.getName(), sds, entry); + assertCheckWrite(file); + assertCheckWrite(dir.resolve(entry)); + sds.move(entry, sds, file.getName()); // restore file + + // newDirectoryStream + entry = Paths.get("subdir1234"); + dir.resolve(entry).createDirectory(); + try { + prepare(); + sds.newDirectoryStream(entry).close(); + assertCheckRead(dir.resolve(entry)); + } finally { + dir.resolve(entry).delete(); + } + + // getFileAttributeView to access attributes of directory + testBasicFileAttributeView(sds + .getFileAttributeView(BasicFileAttributeView.class), dir); + testPosixFileAttributeView(sds + .getFileAttributeView(PosixFileAttributeView.class), dir); + + // getFileAttributeView to access attributes of entry + entry = file.getName(); + testBasicFileAttributeView(sds + .getFileAttributeView(entry, BasicFileAttributeView.class), file); + testPosixFileAttributeView(sds + .getFileAttributeView(entry, PosixFileAttributeView.class), file); + + } else { + System.out.println("SecureDirectoryStream not tested"); + } + + } finally { + stream.close(); + } + + // -- toAbsolutePath -- + + prepare(); + file.getName().toAbsolutePath(); + assertCheckPropertyAccess("user.dir"); + + // -- toRealPath -- + + prepare(); + file.toRealPath(true); + assertCheckRead(file); + + prepare(); + file.toRealPath(false); + assertCheckRead(file); + + prepare(); + Paths.get(".").toRealPath(true); + assertCheckPropertyAccess("user.dir"); + + prepare(); + Paths.get(".").toRealPath(false); + assertCheckPropertyAccess("user.dir"); + + // -- register -- + + WatchService watcher = FileSystems.getDefault().newWatchService(); + try { + prepare(); + dir.register(watcher, StandardWatchEventKind.ENTRY_DELETE); + assertCheckRead(dir); + } finally { + watcher.close(); + } + + // -- getAttribute/setAttribute/readAttributes -- + + prepare(); + file.getAttribute("size"); + assertCheckRead(file); + + prepare(); + file.setAttribute("lastModifiedTime", + FileTime.fromMillis(System.currentTimeMillis())); + assertCheckWrite(file); + + prepare(); + file.readAttributes("*"); + assertCheckRead(file); + + // -- BasicFileAttributeView -- + testBasicFileAttributeView(file + .getFileAttributeView(BasicFileAttributeView.class), file); + + // -- PosixFileAttributeView -- + + { + PosixFileAttributeView view = + file.getFileAttributeView(PosixFileAttributeView.class); + if (view != null && + file.getFileStore().supportsFileAttributeView(PosixFileAttributeView.class)) + { + testPosixFileAttributeView(view, file); + } else { + System.out.println("PosixFileAttributeView not tested"); + } + } + + // -- DosFileAttributeView -- + + { + DosFileAttributeView view = + file.getFileAttributeView(DosFileAttributeView.class); + if (view != null && + file.getFileStore().supportsFileAttributeView(DosFileAttributeView.class)) + { + prepare(); + view.readAttributes(); + assertCheckRead(file); + + prepare(); + view.setArchive(false); + assertCheckWrite(file); + + prepare(); + view.setHidden(false); + assertCheckWrite(file); + + prepare(); + view.setReadOnly(false); + assertCheckWrite(file); + + prepare(); + view.setSystem(false); + assertCheckWrite(file); + } else { + System.out.println("DosFileAttributeView not tested"); + } + } + + // -- FileOwnerAttributeView -- + + { + FileOwnerAttributeView view = + file.getFileAttributeView(FileOwnerAttributeView.class); + if (view != null && + file.getFileStore().supportsFileAttributeView(FileOwnerAttributeView.class)) + { + prepare(); + UserPrincipal owner = view.getOwner(); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + + prepare(); + view.setOwner(owner); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + + } else { + System.out.println("FileOwnerAttributeView not tested"); + } + } + + // -- UserDefinedFileAttributeView -- + + { + UserDefinedFileAttributeView view = + file.getFileAttributeView(UserDefinedFileAttributeView.class); + if (view != null && + file.getFileStore().supportsFileAttributeView(UserDefinedFileAttributeView.class)) + { + prepare(); + view.write("test", ByteBuffer.wrap(new byte[100])); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, + "accessUserDefinedAttributes"); + + prepare(); + view.read("test", ByteBuffer.allocate(100)); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, + "accessUserDefinedAttributes"); + + prepare(); + view.size("test"); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, + "accessUserDefinedAttributes"); + + prepare(); + view.list(); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, + "accessUserDefinedAttributes"); + + prepare(); + view.delete("test"); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, + "accessUserDefinedAttributes"); + } else { + System.out.println("UserDefinedFileAttributeView not tested"); + } + } + + // -- AclFileAttributeView -- + { + AclFileAttributeView view = + file.getFileAttributeView(AclFileAttributeView.class); + if (view != null && + file.getFileStore().supportsFileAttributeView(AclFileAttributeView.class)) + { + prepare(); + List acl = view.getAcl(); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + prepare(); + view.setAcl(acl); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + } else { + System.out.println("AclFileAttributeView not tested"); + } + } + + // -- UserPrincipalLookupService + + UserPrincipalLookupService lookupService = + FileSystems.getDefault().getUserPrincipalLookupService(); + UserPrincipal owner = Attributes.getOwner(file); + + prepare(); + lookupService.lookupPrincipalByName(owner.getName()); + assertCheckPermission(RuntimePermission.class, + "lookupUserInformation"); + + try { + UserPrincipal group = Attributes.readPosixFileAttributes(file).group(); + prepare(); + lookupService.lookupPrincipalByGroupName(group.getName()); + assertCheckPermission(RuntimePermission.class, + "lookupUserInformation"); + } catch (UnsupportedOperationException ignore) { + System.out.println("lookupPrincipalByGroupName not tested"); + } + + + } finally { + file.deleteIfExists(); + } + } +} diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/nio/file/Path/Misc.java --- a/jdk/test/java/nio/file/Path/Misc.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/test/java/nio/file/Path/Misc.java Wed Jul 05 16:59:43 2017 +0200 @@ -22,7 +22,7 @@ */ /* @test - * @bug 4313887 6838333 6866804 + * @bug 4313887 6838333 6867101 * @summary Unit test for java.nio.file.Path for miscellenous methods not * covered by other tests * @library .. diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/nio/file/PathMatcher/Basic.java --- a/jdk/test/java/nio/file/PathMatcher/Basic.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/test/java/nio/file/PathMatcher/Basic.java Wed Jul 05 16:59:43 2017 +0200 @@ -22,7 +22,7 @@ */ /* @test - * @bug 4313887 + * @bug 4313887 6866397 * @summary Unit test for java.nio.file.PathMatcher */ @@ -68,6 +68,20 @@ } } + static void assertRegExMatch(String path, String pattern) { + System.out.format("Test regex pattern: %s", pattern); + Path file = Paths.get(path); + boolean matched = file.getFileSystem() + .getPathMatcher("regex:" + pattern).matches(file); + if (matched) { + System.out.println(" OKAY"); + } else { + System.out.println(" ==> UNEXPECTED RESULT!"); + failures++; + } + } + + public static void main(String[] args) { // basic assertMatch("foo.html", "foo.html"); @@ -140,21 +154,13 @@ assertMatch("one*two", "one\\*two"); } - + // regex syntax + assertRegExMatch("foo.html", ".*\\.html"); - // regex syntax - { - String pattern = ".*\\.html"; - System.out.format("Test regex pattern: %s", pattern); - Path file = Paths.get("foo.html"); - boolean matched = file.getFileSystem() - .getPathMatcher("regex:" + pattern).matches(file); - if (matched) { - System.out.println(" OKAY"); - } else { - System.out.println(" ==> UNEXPECTED RESULT!"); - failures++; - } + if (System.getProperty("os.name").startsWith("Windows")) { + assertRegExMatch("foo012", "foo\\d+"); + assertRegExMatch("fo o", "fo\\so"); + assertRegExMatch("foo", "\\w+"); } // unknown syntax diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/util/prefs/CommentsInXml.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/prefs/CommentsInXml.java Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,60 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 4619564 + * @summary XMl Comments in Preferences File lead to ClassCastException + * @author kladko + */ + +import java.io.*; +import java.util.prefs.*; + +public class CommentsInXml { + + public static void main(String[] argv) throws Exception { + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + bos.write(new String( + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + ).getBytes()); + + Preferences ur = Preferences.userRoot(); + ur.importPreferences(new ByteArrayInputStream(bos.toByteArray())); + ur.node("hlrAgent").removeNode(); // clean + } +} diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/util/prefs/ConflictInFlush.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/prefs/ConflictInFlush.java Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,49 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 4703132 + * @summary flush() throws an IllegalStateException on a removed node + * @author Sucheta Dambalkar + */ + +import java.util.prefs.*; + +public final class ConflictInFlush{ + + public static void main(String args[]) { + Preferences root = Preferences.userRoot(); + try { + Preferences node = root.node("1/2/3"); + node.flush(); + System.out.println("Node "+node+" has been created"); + System.out.println("Removing node "+node); + node.removeNode(); + node.flush(); + }catch (BackingStoreException bse){ + bse.printStackTrace(); + } + + } +} diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/util/prefs/ExportNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/prefs/ExportNode.java Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,53 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +/* + * @test + * @bug 4387136 4947349 + * @summary Due to a bug in XMLSupport.putPreferencesInXml(...), + * node's keys would not get exported. + * @author Konstantin Kladko + */ +import java.util.prefs.*; +import java.io.*; + +public class ExportNode { + public static void main(String[] args) throws + BackingStoreException, IOException { + Preferences N1 = Preferences.userRoot().node("ExportNodeTest1"); + N1.put("ExportNodeTestName1","ExportNodeTestValue1"); + Preferences N2 = N1.node("ExportNodeTest2"); + N2.put("ExportNodeTestName2","ExportNodeTestValue2"); + ByteArrayOutputStream exportStream = new ByteArrayOutputStream(); + N2.exportNode(exportStream); + + // Removal of preference node should always succeed on Solaris/Linux + // by successfully acquiring the appropriate file lock (4947349) + N1.removeNode(); + + if (((exportStream.toString()).lastIndexOf("ExportNodeTestName2")== -1) || + ((exportStream.toString()).lastIndexOf("ExportNodeTestName1")!= -1)) { + } + } +} diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/util/prefs/ExportSubtree.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/prefs/ExportSubtree.java Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,95 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +/* @test + @bug 6203576 4700020 + @summary checks if the output of exportSubtree() is identical to + the output from previous release. + */ + +import java.io.*; +import java.util.prefs.*; + +public class ExportSubtree { + public static void main(String[] args) throws Exception { + try + { + //File f = new File(System.getProperty("test.src", "."), "TestPrefs.xml"); + ByteArrayInputStream bais = new ByteArrayInputStream(importPrefs.getBytes("utf-8")); + Preferences.importPreferences(bais); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Preferences.userRoot().node("testExportSubtree").exportSubtree(baos); + Preferences.userRoot().node("testExportSubtree").removeNode(); + if (!expectedResult.equals(baos.toString())) { + //System.out.print(baos.toString()); + //System.out.print(expectedResult); + throw new IOException("exportSubtree does not output expected result"); + } + } + catch( Exception e ) { + e.printStackTrace(); + } + } + + static String ls = System.getProperty("line.separator"); + static String importPrefs = + "" + + "" + + "" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + ""; + + static String expectedResult = + "" + + ls + "" + + ls + "" + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + " " + + ls + "" + ls; +} diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/util/prefs/PrefsSpi.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/prefs/PrefsSpi.java Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,44 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +import java.util.prefs.Preferences; + +/* + * main class used by regtest PrefsSpi.sh + */ +public class PrefsSpi { + + public static void main (String[] args) throws Exception { + if (args.length != 1) + throw new Exception("Usage: java PrefsSpi REGEXP"); + + String className = Preferences.userRoot().getClass().getName(); + System.out.printf("className=%s%n", className); + + if (! className.matches(args[0])) + throw new Exception("Preferences class name \"" + className + + "\" does not match regular expression \"" + + args[0] + "\"."); + } +} diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/util/prefs/PrefsSpi.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/prefs/PrefsSpi.sh Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,100 @@ +#!/bin/sh + +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @bug 4991526 6514993 +# @summary Unit test for Preferences jar providers +# +# @build PrefsSpi +# @run shell PrefsSpi.sh +# @author Martin Buchholz + +# Command-line usage: sh PrefsSpi.sh /path/to/build + +if [ -z "$TESTJAVA" ]; then + if [ $# -lt 1 ]; then exit 1; fi + TESTJAVA="$1"; shift + TESTSRC="`pwd`" + TESTCLASSES="`pwd`" +fi + + java="$TESTJAVA/bin/java" +javac="$TESTJAVA/bin/javac" + jar="$TESTJAVA/bin/jar" + +Die() { printf "%s\n" "$*"; exit 1; } + +Sys() { + printf "%s\n" "$*"; "$@"; rc="$?"; + test "$rc" -eq 0 || Die "Command \"$*\" failed with exitValue $rc"; +} + +cat > StubPreferences.java <<'EOF' +import java.util.prefs.*; + +public class StubPreferences extends AbstractPreferences { + public StubPreferences() { super(null, ""); } + public String getSpi(String x) { return null; } + public void putSpi(String x, String y) { } + public void removeSpi(String x) { } + public AbstractPreferences childSpi(String x) { return null; } + public void removeNodeSpi() { } + public String[] keysSpi() { return null; } + public String[] childrenNamesSpi() { return null; } + public void syncSpi() { } + public void flushSpi() { } +} +EOF + +cat > StubPreferencesFactory.java <<'EOF' +import java.util.prefs.*; + +public class StubPreferencesFactory implements PreferencesFactory { + public Preferences userRoot() { return new StubPreferences(); } + public Preferences systemRoot() { return new StubPreferences(); } +} +EOF + +Sys rm -rf jarDir extDir +Sys mkdir -p jarDir/META-INF/services extDir +echo "StubPreferencesFactory" \ + > "jarDir/META-INF/services/java.util.prefs.PreferencesFactory" +Sys "$javac" -d jarDir StubPreferencesFactory.java StubPreferences.java + +(cd jarDir && "$jar" "cf" "../extDir/PrefsSpi.jar" ".") + +case "`uname`" in Windows*|CYGWIN* ) CPS=';';; *) CPS=':';; esac + +Sys "$java" "-cp" "$TESTCLASSES${CPS}extDir/PrefsSpi.jar" \ + -Djava.util.prefs.PreferencesFactory=StubPreferencesFactory \ + PrefsSpi "StubPreferences" +Sys "$java" "-cp" "$TESTCLASSES" \ + PrefsSpi "java.util.prefs.*" +Sys "$java" "-cp" "$TESTCLASSES${CPS}extDir/PrefsSpi.jar" \ + PrefsSpi "StubPreferences" +Sys "$java" "-cp" "$TESTCLASSES" "-Djava.ext.dirs=extDir" \ + PrefsSpi "StubPreferences" + +rm -rf jarDir extDir diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/util/prefs/RemoveReadOnlyNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/prefs/RemoveReadOnlyNode.java Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +/* @test + @bug 6178148 + @summary check if wrong exception gets thrown if one of the child + nodes is readonly on underlying filesystem when node is + being removed. + */ + +import java.io.*; +import java.util.prefs.*; + +public class RemoveReadOnlyNode { + public static void main(String[] args) throws Exception { + String osName = System.getProperty("os.name"); + if (osName.startsWith("Windows")) + return; + Preferences root = Preferences.userRoot(); + Preferences node1 = root.node("node1"); + Preferences node1A = node1.node("node1A"); + Preferences node1B = node1.node("node1B"); + node1B.put("mykey", "myvalue"); + node1.flush(); + String node1BDirName = System.getProperty("user.home") + + "/.java/.userPrefs" + + "/node1/node1B"; + File node1BDir = new File(node1BDirName); + node1BDir.setReadOnly(); + try { + node1.removeNode(); + } + catch (BackingStoreException ex) { + //expected exception + } finally { + Runtime.getRuntime().exec("chmod 755 " + node1BDirName).waitFor(); + try { + node1.removeNode(); + } catch (Exception e) {} + } + } +} diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/util/prefs/RemoveUnregedListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/prefs/RemoveUnregedListener.java Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +/* @test + * @bug 4705094 + * @summary Checks if correct exception gets thrown when removing an + * unregistered NodeChangeListener . + */ + +import java.util.prefs.*; +import java.util.*; + +public class RemoveUnregedListener { + public static void main(String[] args) throws Exception { + Preferences userRoot = null; + Preferences N1 = null; + NodeChangeListenerTestAdd ncl = new NodeChangeListenerTestAdd(); + NodeChangeListenerTestAdd ncl2 = new NodeChangeListenerTestAdd(); + NodeChangeListenerTestAdd ncl3 = new NodeChangeListenerTestAdd(); + try { + userRoot = Preferences.userRoot(); + N1 = userRoot.node("N1"); + userRoot.flush(); + + //add ncl nc2 + N1.addNodeChangeListener(ncl); + N1.addNodeChangeListener(ncl2); + N1.removeNodeChangeListener(ncl3); + throw new RuntimeException(); + } catch (IllegalArgumentException iae) { + System.out.println("Test Passed!"); + } catch (Exception e) { + System.out.println("Test Failed"); + throw e; + } + } + +} +class NodeChangeListenerTestAdd implements NodeChangeListener { + public void childAdded(NodeChangeEvent evt) {} + public void childRemoved(NodeChangeEvent evt) {} +} diff -r ae9b655e7393 -r e17115919cc7 jdk/test/java/util/prefs/SerializeExceptions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/prefs/SerializeExceptions.java Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,48 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +/* + * @test + * @bug 4811356 + * @summary Prefs exceptions were unintentionally not serializable + * @author Josh Bloch + */ + +import java.util.prefs.*; +import java.io.*; + +public class SerializeExceptions { + public static void main(String args[]) throws Exception { + test(new BackingStoreException("Hi")); + test(new InvalidPreferencesFormatException("Mom!")); + } + + static void test(Object o) throws IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(bos); + out.writeObject(o); + out.flush(); + out.close(); + } +} diff -r ae9b655e7393 -r e17115919cc7 jdk/test/sun/nio/cs/FindCanEncodeBugs.java --- a/jdk/test/sun/nio/cs/FindCanEncodeBugs.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/test/sun/nio/cs/FindCanEncodeBugs.java Wed Jul 05 16:59:43 2017 +0200 @@ -22,7 +22,7 @@ */ /* @test - @bug 5066863 5066867 5066874 5066879 5066884 5066887 5065777 + @bug 5066863 5066867 5066874 5066879 5066884 5066887 5065777 6730652 @summary canEncode() false iff encode() throws CharacterCodingException @run main/timeout=1200 FindCanEncodeBugs @author Martin Buchholz @@ -52,9 +52,7 @@ String csn = e.getKey(); Charset cs = e.getValue(); - if (! cs.canEncode() || - csn.matches("x-COMPOUND_TEXT") || - csn.matches("x-ISO-2022-CN-CNS")) // ISO2022_CN_CNS supports less + if (! cs.canEncode() || csn.matches("x-COMPOUND_TEXT")) continue; //System.out.println(csn); diff -r ae9b655e7393 -r e17115919cc7 jdk/test/sun/security/ec/TestEC.java --- a/jdk/test/sun/security/ec/TestEC.java Tue Sep 01 23:44:41 2009 +0100 +++ b/jdk/test/sun/security/ec/TestEC.java Wed Jul 05 16:59:43 2017 +0200 @@ -53,7 +53,7 @@ long start = System.currentTimeMillis(); new TestECDH().main(p); new TestECDSA().main(p); - //new TestCurves().main(p); + new TestCurves().main(p); new TestKeyFactory().main(p); new TestECGenSpec().main(p); new ReadPKCS12().main(p); diff -r ae9b655e7393 -r e17115919cc7 jdk/test/sun/security/krb5/ktab/HighestKvno.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/krb5/ktab/HighestKvno.java Wed Jul 05 16:59:43 2017 +0200 @@ -0,0 +1,235 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * @test + * @bug 6867665 + * @bug 6875033 + * @summary Problem with keytabs with multiple kvno's (key versions) + */ + +import sun.security.krb5.internal.ktab.*; +import sun.security.krb5.*; +import java.io.File; +import java.io.FileOutputStream; + +public class HighestKvno { + + public static void main(String[] args) throws Exception { + // kt is a keytab including these entries: + // + // me@MAD.LOCAL: Type: 3, KVNO: 4 + // me@MAD.LOCAL: Type: 23, KVNO: 4 + // me@MAD.LOCAL: Type: 16, KVNO: 4 + // me@MAD.LOCAL: Type: 1, KVNO: 5 + // me@MAD.LOCAL: Type: 17, KVNO: 5 + // me@MAD.LOCAL: Type: 18, KVNO: 5 + // me@MAD.LOCAL: Type: 1, KVNO: 3 + // me@MAD.LOCAL: Type: 17, KVNO: 3 + // me@MAD.LOCAL: Type: 18, KVNO: 3 + // he@MAD.LOCAL: Type: 1, KVNO: 1 + // he@MAD.LOCAL: Type: 17, KVNO: 1 + // he@MAD.LOCAL: Type: 18, KVNO: 1 + // + // This file is created with these steps: + // 1. Modify JRE's Ktab.java so that adding new entries + // does not remove the old one. + // 2. Run the modified Ktab to create 4 sets of keys + // 3. Manually hex edit the KVNO as above + + byte[] kt = { + (byte)0x05, (byte)0x02, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x26, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x09, (byte)0x4D, (byte)0x41, + (byte)0x44, (byte)0x2E, (byte)0x4C, (byte)0x4F, + (byte)0x43, (byte)0x41, (byte)0x4C, (byte)0x00, + (byte)0x02, (byte)0x6D, (byte)0x65, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x4A, + (byte)0x79, (byte)0x45, (byte)0xCD, (byte)0x04, + (byte)0x00, (byte)0x03, (byte)0x00, (byte)0x08, + (byte)0xE6, (byte)0xB0, (byte)0x07, (byte)0xA8, + (byte)0x5B, (byte)0xF8, (byte)0x73, (byte)0xAD, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x2E, + (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x09, + (byte)0x4D, (byte)0x41, (byte)0x44, (byte)0x2E, + (byte)0x4C, (byte)0x4F, (byte)0x43, (byte)0x41, + (byte)0x4C, (byte)0x00, (byte)0x02, (byte)0x6D, + (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x4A, (byte)0x79, (byte)0x45, + (byte)0xCD, (byte)0x04, (byte)0x00, (byte)0x17, + (byte)0x00, (byte)0x10, (byte)0x50, (byte)0x92, + (byte)0x01, (byte)0x6B, (byte)0xCF, (byte)0x5A, + (byte)0x2A, (byte)0x7A, (byte)0x4F, (byte)0xE8, + (byte)0x39, (byte)0xD9, (byte)0x90, (byte)0xB5, + (byte)0x9C, (byte)0xEB, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x36, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x09, (byte)0x4D, (byte)0x41, + (byte)0x44, (byte)0x2E, (byte)0x4C, (byte)0x4F, + (byte)0x43, (byte)0x41, (byte)0x4C, (byte)0x00, + (byte)0x02, (byte)0x6D, (byte)0x65, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x4A, + (byte)0x79, (byte)0x45, (byte)0xCD, (byte)0x04, + (byte)0x00, (byte)0x10, (byte)0x00, (byte)0x18, + (byte)0xDF, (byte)0xDF, (byte)0x62, (byte)0x86, + (byte)0x37, (byte)0xCE, (byte)0x29, (byte)0xBA, + (byte)0xBC, (byte)0x23, (byte)0x15, (byte)0xDC, + (byte)0x86, (byte)0x7C, (byte)0xB6, (byte)0x89, + (byte)0x25, (byte)0x25, (byte)0xCD, (byte)0x4A, + (byte)0x9B, (byte)0xCE, (byte)0xF4, (byte)0xAE, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x26, + (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x09, + (byte)0x4D, (byte)0x41, (byte)0x44, (byte)0x2E, + (byte)0x4C, (byte)0x4F, (byte)0x43, (byte)0x41, + (byte)0x4C, (byte)0x00, (byte)0x02, (byte)0x6D, + (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x4A, (byte)0x79, (byte)0x4B, + (byte)0x5E, (byte)0x05, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x08, (byte)0xE6, (byte)0xB0, + (byte)0x07, (byte)0xA8, (byte)0x5B, (byte)0xF8, + (byte)0x73, (byte)0xAD, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x2E, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x09, (byte)0x4D, (byte)0x41, + (byte)0x44, (byte)0x2E, (byte)0x4C, (byte)0x4F, + (byte)0x43, (byte)0x41, (byte)0x4C, (byte)0x00, + (byte)0x02, (byte)0x6D, (byte)0x65, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x4A, + (byte)0x79, (byte)0x4B, (byte)0x5E, (byte)0x05, + (byte)0x00, (byte)0x11, (byte)0x00, (byte)0x10, + (byte)0xEA, (byte)0xF5, (byte)0xA8, (byte)0x36, + (byte)0xA5, (byte)0x3E, (byte)0x5F, (byte)0x5C, + (byte)0x26, (byte)0xE9, (byte)0xDD, (byte)0x8B, + (byte)0x8C, (byte)0xE8, (byte)0x92, (byte)0x9C, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x3E, + (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x09, + (byte)0x4D, (byte)0x41, (byte)0x44, (byte)0x2E, + (byte)0x4C, (byte)0x4F, (byte)0x43, (byte)0x41, + (byte)0x4C, (byte)0x00, (byte)0x02, (byte)0x6D, + (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x4A, (byte)0x79, (byte)0x4B, + (byte)0x5E, (byte)0x05, (byte)0x00, (byte)0x12, + (byte)0x00, (byte)0x20, (byte)0x68, (byte)0xBE, + (byte)0xD4, (byte)0x17, (byte)0x3A, (byte)0x06, + (byte)0xE0, (byte)0x0C, (byte)0x62, (byte)0x11, + (byte)0xB7, (byte)0x53, (byte)0x1B, (byte)0x3E, + (byte)0xB2, (byte)0x6B, (byte)0x0D, (byte)0x48, + (byte)0xD8, (byte)0x52, (byte)0x5A, (byte)0x4C, + (byte)0xBE, (byte)0x24, (byte)0xBB, (byte)0x3D, + (byte)0xC1, (byte)0x74, (byte)0x69, (byte)0xDA, + (byte)0x34, (byte)0x98, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x26, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x09, (byte)0x4D, (byte)0x41, + (byte)0x44, (byte)0x2E, (byte)0x4C, (byte)0x4F, + (byte)0x43, (byte)0x41, (byte)0x4C, (byte)0x00, + (byte)0x02, (byte)0x6D, (byte)0x65, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x4A, + (byte)0x79, (byte)0x51, (byte)0x27, (byte)0x03, + (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x08, + (byte)0xE6, (byte)0xB0, (byte)0x07, (byte)0xA8, + (byte)0x5B, (byte)0xF8, (byte)0x73, (byte)0xAD, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x2E, + (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x09, + (byte)0x4D, (byte)0x41, (byte)0x44, (byte)0x2E, + (byte)0x4C, (byte)0x4F, (byte)0x43, (byte)0x41, + (byte)0x4C, (byte)0x00, (byte)0x02, (byte)0x6D, + (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x4A, (byte)0x79, (byte)0x51, + (byte)0x27, (byte)0x03, (byte)0x00, (byte)0x11, + (byte)0x00, (byte)0x10, (byte)0xEA, (byte)0xF5, + (byte)0xA8, (byte)0x36, (byte)0xA5, (byte)0x3E, + (byte)0x5F, (byte)0x5C, (byte)0x26, (byte)0xE9, + (byte)0xDD, (byte)0x8B, (byte)0x8C, (byte)0xE8, + (byte)0x92, (byte)0x9C, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x3E, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x09, (byte)0x4D, (byte)0x41, + (byte)0x44, (byte)0x2E, (byte)0x4C, (byte)0x4F, + (byte)0x43, (byte)0x41, (byte)0x4C, (byte)0x00, + (byte)0x02, (byte)0x6D, (byte)0x65, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x4A, + (byte)0x79, (byte)0x51, (byte)0x27, (byte)0x03, + (byte)0x00, (byte)0x12, (byte)0x00, (byte)0x20, + (byte)0x68, (byte)0xBE, (byte)0xD4, (byte)0x17, + (byte)0x3A, (byte)0x06, (byte)0xE0, (byte)0x0C, + (byte)0x62, (byte)0x11, (byte)0xB7, (byte)0x53, + (byte)0x1B, (byte)0x3E, (byte)0xB2, (byte)0x6B, + (byte)0x0D, (byte)0x48, (byte)0xD8, (byte)0x52, + (byte)0x5A, (byte)0x4C, (byte)0xBE, (byte)0x24, + (byte)0xBB, (byte)0x3D, (byte)0xC1, (byte)0x74, + (byte)0x69, (byte)0xDA, (byte)0x34, (byte)0x98, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x26, + (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x09, + (byte)0x4D, (byte)0x41, (byte)0x44, (byte)0x2E, + (byte)0x4C, (byte)0x4F, (byte)0x43, (byte)0x41, + (byte)0x4C, (byte)0x00, (byte)0x02, (byte)0x68, + (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x4A, (byte)0x79, (byte)0x54, + (byte)0xC7, (byte)0x01, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x08, (byte)0x85, (byte)0x5B, + (byte)0xE3, (byte)0x13, (byte)0x3E, (byte)0xF8, + (byte)0x76, (byte)0xEC, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x2E, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x09, (byte)0x4D, (byte)0x41, + (byte)0x44, (byte)0x2E, (byte)0x4C, (byte)0x4F, + (byte)0x43, (byte)0x41, (byte)0x4C, (byte)0x00, + (byte)0x02, (byte)0x68, (byte)0x65, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x4A, + (byte)0x79, (byte)0x54, (byte)0xC7, (byte)0x01, + (byte)0x00, (byte)0x11, (byte)0x00, (byte)0x10, + (byte)0xEC, (byte)0xCC, (byte)0x16, (byte)0xCD, + (byte)0xE8, (byte)0x51, (byte)0x46, (byte)0x4C, + (byte)0x1B, (byte)0x57, (byte)0xAE, (byte)0x19, + (byte)0xC3, (byte)0xD2, (byte)0x55, (byte)0x1B, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x3E, + (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x09, + (byte)0x4D, (byte)0x41, (byte)0x44, (byte)0x2E, + (byte)0x4C, (byte)0x4F, (byte)0x43, (byte)0x41, + (byte)0x4C, (byte)0x00, (byte)0x02, (byte)0x68, + (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x4A, (byte)0x79, (byte)0x54, + (byte)0xC7, (byte)0x01, (byte)0x00, (byte)0x12, + (byte)0x00, (byte)0x20, (byte)0xAE, (byte)0xBA, + (byte)0xCB, (byte)0xF5, (byte)0xA8, (byte)0x09, + (byte)0xC1, (byte)0xB0, (byte)0x2C, (byte)0x2A, + (byte)0x3D, (byte)0x96, (byte)0x2C, (byte)0x2D, + (byte)0xF5, (byte)0xFE, (byte)0x65, (byte)0xEC, + (byte)0x75, (byte)0x72, (byte)0x5B, (byte)0x46, + (byte)0x84, (byte)0xD7, (byte)0x49, (byte)0x3E, + (byte)0xF2, (byte)0x27, (byte)0x32, (byte)0x69, + (byte)0x75, (byte)0x9B, + }; + System.setProperty("java.security.krb5.conf", + new File(System.getProperty("test.src"), + "../krb5.conf").getAbsolutePath()); + FileOutputStream fout = new FileOutputStream("kt"); + fout.write(kt); + fout.close(); + KeyTab ktab = KeyTab.getInstance("kt"); + PrincipalName pn = new PrincipalName("me@MAD.LOCAL"); + EncryptionKey[] keys = ktab.readServiceKeys(pn); + if (keys[0].getKeyVersionNumber() != 5) { + throw new Exception("Highest not first"); + } + if (ktab.readServiceKey(pn).getKeyVersionNumber() != 5) { + throw new Exception("Highest not chosen"); + } + new File("kt").delete(); + } +} diff -r ae9b655e7393 -r e17115919cc7 make/Defs-internal.gmk --- a/make/Defs-internal.gmk Tue Sep 01 23:44:41 2009 +0100 +++ b/make/Defs-internal.gmk Wed Jul 05 16:59:43 2017 +0200 @@ -133,7 +133,11 @@ # Do we build the source and openjdk binary plug bundles? BUNDLE_RULES = $(JDK_TOPDIR)/make/closed/bundles.gmk -BUNDLE_RULES_AVAILABLE := $(call MkExists,$(BUNDLE_RULES)) +ifeq ($(SKIP_BUNDLES_BUILD), true) + BUNDLE_RULES_AVAILABLE := false +else + BUNDLE_RULES_AVAILABLE := $(call MkExists,$(BUNDLE_RULES)) +endif # Current things we do NOT build for OPENJDK ifdef OPENJDK