--- a/.hgtags-top-repo Fri Nov 20 15:40:23 2015 -0800
+++ b/.hgtags-top-repo Wed Jul 05 21:02:29 2017 +0200
@@ -335,3 +335,4 @@
cf1dc4c035fb84693d4ae5ad818785cb4d1465d1 jdk9-b90
122142a185381ce5cea959bf13b923d8cc333628 jdk9-b91
106c06398f7ab330eef9e335fbd3a5a8ead23b77 jdk9-b92
+331fda57dfd323c61804ba0472776790de572937 jdk9-b93
--- a/corba/.hgtags Fri Nov 20 15:40:23 2015 -0800
+++ b/corba/.hgtags Wed Jul 05 21:02:29 2017 +0200
@@ -335,3 +335,4 @@
29cc8228d62319af21cad7c90817671e0813b6bd jdk9-b90
75843e0a9371d445a3c9b440bab85e50b5dc287c jdk9-b91
f7d70caad89ad0c43bb057bca0aad6f17ce05a6a jdk9-b92
+27e9c8d8091e2447ea7ef3e3103e9b7dd286e03a jdk9-b93
--- a/hotspot/.hgtags Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/.hgtags Wed Jul 05 21:02:29 2017 +0200
@@ -495,3 +495,4 @@
7fe46dc64bb3a8df554b24cde0153ffb24f39c5e jdk9-b90
3fd5c2ca4c20c183628b6dbeb8df821a961419e3 jdk9-b91
53cb98d68a1aeb08d29c89d6da748de60c448e37 jdk9-b92
+d8b24776484cc4dfd19f50b23eaa18a80a161371 jdk9-b93
--- a/hotspot/agent/src/os/linux/libproc_impl.c Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/agent/src/os/linux/libproc_impl.c Wed Jul 05 21:02:29 2017 +0200
@@ -38,6 +38,7 @@
int fd;
char alt_path[PATH_MAX + 1], *alt_path_end;
const char *s;
+ int free_space;
if (!alt_root_initialized) {
alt_root_initialized = -1;
@@ -48,14 +49,22 @@
return open(name, O_RDONLY);
}
- strcpy(alt_path, alt_root);
+
+ if (strlen(alt_root) + strlen(name) < PATH_MAX) {
+ // Buffer too small.
+ return -1;
+ }
+
+ strncpy(alt_path, alt_root, PATH_MAX);
+ alt_path[PATH_MAX] = '\0';
alt_path_end = alt_path + strlen(alt_path);
+ free_space = PATH_MAX + 1 - (alt_path_end-alt_path);
- // Strip path items one by one and try to open file with alt_root prepended
+ // Strip path items one by one and try to open file with alt_root prepended.
s = name;
while (1) {
- strcat(alt_path, s);
- s += 1;
+ strncat(alt_path, s, free_space);
+ s += 1; // Skip /.
fd = open(alt_path, O_RDONLY);
if (fd >= 0) {
@@ -70,7 +79,8 @@
break;
}
- *alt_path_end = 0;
+ // Cut off what we appended above.
+ *alt_path_end = '\0';
}
return -1;
--- a/hotspot/agent/src/os/linux/ps_core.c Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/agent/src/os/linux/ps_core.c Wed Jul 05 21:02:29 2017 +0200
@@ -774,72 +774,78 @@
// process segments from interpreter (ld.so or ld-linux.so)
static bool read_interp_segments(struct ps_prochandle* ph) {
- ELF_EHDR interp_ehdr;
+ ELF_EHDR interp_ehdr;
- if (read_elf_header(ph->core->interp_fd, &interp_ehdr) != true) {
- print_debug("interpreter is not a valid ELF file\n");
- return false;
- }
+ if (read_elf_header(ph->core->interp_fd, &interp_ehdr) != true) {
+ print_debug("interpreter is not a valid ELF file\n");
+ return false;
+ }
- if (read_lib_segments(ph, ph->core->interp_fd, &interp_ehdr, ph->core->ld_base_addr) != true) {
- print_debug("can't read segments of interpreter\n");
- return false;
- }
+ if (read_lib_segments(ph, ph->core->interp_fd, &interp_ehdr, ph->core->ld_base_addr) != true) {
+ print_debug("can't read segments of interpreter\n");
+ return false;
+ }
- return true;
+ return true;
}
// process segments of a a.out
static bool read_exec_segments(struct ps_prochandle* ph, ELF_EHDR* exec_ehdr) {
- int i = 0;
- ELF_PHDR* phbuf = NULL;
- ELF_PHDR* exec_php = NULL;
+ int i = 0;
+ ELF_PHDR* phbuf = NULL;
+ ELF_PHDR* exec_php = NULL;
- if ((phbuf = read_program_header_table(ph->core->exec_fd, exec_ehdr)) == NULL)
- return false;
+ if ((phbuf = read_program_header_table(ph->core->exec_fd, exec_ehdr)) == NULL) {
+ return false;
+ }
- for (exec_php = phbuf, i = 0; i < exec_ehdr->e_phnum; i++) {
- switch (exec_php->p_type) {
+ for (exec_php = phbuf, i = 0; i < exec_ehdr->e_phnum; i++) {
+ switch (exec_php->p_type) {
- // add mappings for PT_LOAD segments
- case PT_LOAD: {
- // add only non-writable segments of non-zero filesz
- if (!(exec_php->p_flags & PF_W) && exec_php->p_filesz != 0) {
- if (add_map_info(ph, ph->core->exec_fd, exec_php->p_offset, exec_php->p_vaddr, exec_php->p_filesz) == NULL) goto err;
- }
- break;
- }
+ // add mappings for PT_LOAD segments
+ case PT_LOAD: {
+ // add only non-writable segments of non-zero filesz
+ if (!(exec_php->p_flags & PF_W) && exec_php->p_filesz != 0) {
+ if (add_map_info(ph, ph->core->exec_fd, exec_php->p_offset, exec_php->p_vaddr, exec_php->p_filesz) == NULL) goto err;
+ }
+ break;
+ }
- // read the interpreter and it's segments
- case PT_INTERP: {
- char interp_name[BUF_SIZE];
+ // read the interpreter and it's segments
+ case PT_INTERP: {
+ char interp_name[BUF_SIZE + 1];
- pread(ph->core->exec_fd, interp_name, MIN(exec_php->p_filesz, BUF_SIZE), exec_php->p_offset);
- print_debug("ELF interpreter %s\n", interp_name);
- // read interpreter segments as well
- if ((ph->core->interp_fd = pathmap_open(interp_name)) < 0) {
- print_debug("can't open runtime loader\n");
- goto err;
- }
- break;
- }
+ // BUF_SIZE is PATH_MAX + NAME_MAX + 1.
+ if (exec_php->p_filesz > BUF_SIZE) {
+ goto err;
+ }
+ pread(ph->core->exec_fd, interp_name, exec_php->p_filesz, exec_php->p_offset);
+ interp_name[exec_php->p_filesz] = '\0';
+ print_debug("ELF interpreter %s\n", interp_name);
+ // read interpreter segments as well
+ if ((ph->core->interp_fd = pathmap_open(interp_name)) < 0) {
+ print_debug("can't open runtime loader\n");
+ goto err;
+ }
+ break;
+ }
- // from PT_DYNAMIC we want to read address of first link_map addr
- case PT_DYNAMIC: {
- ph->core->dynamic_addr = exec_php->p_vaddr;
- print_debug("address of _DYNAMIC is 0x%lx\n", ph->core->dynamic_addr);
- break;
- }
+ // from PT_DYNAMIC we want to read address of first link_map addr
+ case PT_DYNAMIC: {
+ ph->core->dynamic_addr = exec_php->p_vaddr;
+ print_debug("address of _DYNAMIC is 0x%lx\n", ph->core->dynamic_addr);
+ break;
+ }
- } // switch
- exec_php++;
- } // for
+ } // switch
+ exec_php++;
+ } // for
- free(phbuf);
- return true;
-err:
- free(phbuf);
- return false;
+ free(phbuf);
+ return true;
+ err:
+ free(phbuf);
+ return false;
}
--- a/hotspot/make/aix/makefiles/mapfile-vers-debug Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/make/aix/makefiles/mapfile-vers-debug Wed Jul 05 21:02:29 2017 +0200
@@ -39,7 +39,6 @@
jio_snprintf;
jio_vfprintf;
jio_vsnprintf;
- fork1;
numa_warn;
numa_error;
--- a/hotspot/make/aix/makefiles/mapfile-vers-product Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/make/aix/makefiles/mapfile-vers-product Wed Jul 05 21:02:29 2017 +0200
@@ -34,7 +34,6 @@
jio_snprintf;
jio_vfprintf;
jio_vsnprintf;
- fork1;
numa_warn;
numa_error;
--- a/hotspot/make/aix/makefiles/trace.make Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/make/aix/makefiles/trace.make Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -82,8 +82,7 @@
GENERATE_CODE= \
$(QUIETLY) echo $(LOG_INFO) Generating $@; \
- $(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@; \
- test -f $@
+ $(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@
$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS)
$(GENERATE_CODE)
--- a/hotspot/make/bsd/makefiles/mapfile-vers-debug Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/make/bsd/makefiles/mapfile-vers-debug Wed Jul 05 21:02:29 2017 +0200
@@ -34,7 +34,6 @@
jio_snprintf;
jio_vfprintf;
jio_vsnprintf;
- fork1;
numa_warn;
numa_error;
--- a/hotspot/make/bsd/makefiles/mapfile-vers-product Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/make/bsd/makefiles/mapfile-vers-product Wed Jul 05 21:02:29 2017 +0200
@@ -34,7 +34,6 @@
jio_snprintf;
jio_vfprintf;
jio_vsnprintf;
- fork1;
numa_warn;
numa_error;
--- a/hotspot/make/bsd/makefiles/trace.make Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/make/bsd/makefiles/trace.make Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -83,8 +83,7 @@
GENERATE_CODE= \
$(QUIETLY) echo $(LOG_INFO) Generating $@; \
- $(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@; \
- test -f $@
+ $(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@
$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS)
$(GENERATE_CODE)
--- a/hotspot/make/hotspot.script Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/make/hotspot.script Wed Jul 05 21:02:29 2017 +0200
@@ -1,6 +1,6 @@
#!/bin/sh
-# Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -156,7 +156,7 @@
export LD_LIBRARY_PATH
fi
-JPARMS="-XXaltjvm=$MYDIR -Dsun.java.launcher.is_altjvm=true $@ $JAVA_ARGS";
+JPARMS="-XXaltjvm=$MYDIR -Dsun.java.launcher.is_altjvm=true";
# Locate the java launcher
LAUNCHER=$JDK/bin/java
@@ -181,8 +181,6 @@
cd `pwd`
handle SIGUSR1 nostop noprint
handle SIGUSR2 nostop noprint
-set args $JPARMS
-file $LAUNCHER
directory $GDBSRCDIR
# Get us to a point where we can set breakpoints in libjvm.so
set breakpoint pending on
@@ -194,11 +192,10 @@
EOF
}
-
case "$MODE" in
gdb)
init_gdb
- $GDB -x $GDBSCR
+ $GDB -x $GDBSCR --args $LAUNCHER $JPARMS "$@" $JAVA_ARGS
rm -f $GDBSCR
;;
gud)
@@ -219,15 +216,15 @@
rm -f $GDBSCR
;;
dbx)
- $DBX -s $HOME/.dbxrc -c "loadobject -load libjvm.so; stop in JNI_CreateJavaVM; run $JPARMS; delete all" $LAUNCHER
+ $DBX -s $HOME/.dbxrc -c "loadobject -load libjvm.so; stop in JNI_CreateJavaVM; run $JPARMS $@ $JAVA_ARGS; delete all" $LAUNCHER
;;
valgrind)
echo Warning: Defaulting to 16Mb heap to make Valgrind run faster, use -Xmx for larger heap
echo
- $VALGRIND --tool=memcheck --leak-check=yes --num-callers=50 $LAUNCHER -Xmx16m $JPARMS
+ $VALGRIND --tool=memcheck --leak-check=yes --num-callers=50 $LAUNCHER -Xmx16m $JPARMS "$@" $JAVA_ARGS
;;
run)
- LD_PRELOAD=$PRELOADING exec $LAUNCHER $JPARMS
+ LD_PRELOAD=$PRELOADING exec $LAUNCHER $JPARMS "$@" $JAVA_ARGS
;;
*)
echo Error: Internal error, unknown launch mode \"$MODE\"
--- a/hotspot/make/linux/makefiles/mapfile-vers-debug Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/make/linux/makefiles/mapfile-vers-debug Wed Jul 05 21:02:29 2017 +0200
@@ -34,7 +34,6 @@
jio_snprintf;
jio_vfprintf;
jio_vsnprintf;
- fork1;
numa_warn;
numa_error;
--- a/hotspot/make/linux/makefiles/mapfile-vers-product Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/make/linux/makefiles/mapfile-vers-product Wed Jul 05 21:02:29 2017 +0200
@@ -34,7 +34,6 @@
jio_snprintf;
jio_vfprintf;
jio_vsnprintf;
- fork1;
numa_warn;
numa_error;
--- a/hotspot/make/linux/makefiles/trace.make Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/make/linux/makefiles/trace.make Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -82,8 +82,7 @@
GENERATE_CODE= \
$(QUIETLY) echo $(LOG_INFO) Generating $@; \
- $(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@; \
- test -f $@
+ $(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@
$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS)
$(GENERATE_CODE)
--- a/hotspot/make/solaris/makefiles/sparcWorks.make Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/make/solaris/makefiles/sparcWorks.make Wed Jul 05 21:02:29 2017 +0200
@@ -550,19 +550,6 @@
#LINK_INTO = LIBJVM
endif
-# Solaris platforms collect lots of redundant file-ident lines,
-# to the point of wasting a significant percentage of file space.
-# (The text is stored in ELF .comment sections, contributed by
-# all "#pragma ident" directives in header and source files.)
-# This command "compresses" the .comment sections simply by
-# removing repeated lines. The data can be extracted from
-# binaries in the field by using "mcs -p libjvm.so" or the older
-# command "what libjvm.so".
-LINK_LIB.CXX/POST_HOOK += $(MCS) -c $@ || exit 1;
-# (The exit 1 is necessary to cause a build failure if the command fails and
-# multiple commands are strung together, and the final semicolon is necessary
-# since the hook must terminate itself as a valid command.)
-
# Also, strip debug and line number information (worth about 1.7Mb).
# If we can create .debuginfo files, then the VM is stripped in vm.make
# and this macro is not used.
--- a/hotspot/make/solaris/makefiles/trace.make Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/make/solaris/makefiles/trace.make Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -78,8 +78,7 @@
GENERATE_CODE= \
$(QUIETLY) echo $(LOG_INFO) Generating $@; \
- $(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@; \
- test -f $@
+ $(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@
$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS)
$(GENERATE_CODE)
--- a/hotspot/make/test/JtregNative.gmk Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/make/test/JtregNative.gmk Wed Jul 05 21:02:29 2017 +0200
@@ -45,6 +45,7 @@
$(HOTSPOT_TOPDIR)/test/runtime/jni/8025979 \
$(HOTSPOT_TOPDIR)/test/runtime/jni/8033445 \
$(HOTSPOT_TOPDIR)/test/runtime/jni/ToStringInInterfaceTest \
+ $(HOTSPOT_TOPDIR)/test/runtime/SameObject \
#
BUILD_HOTSPOT_JTREG_OUTPUT_DIR := $(BUILD_OUTPUT)/support/test/hotspot/jtreg/native
--- a/hotspot/make/windows/makefiles/compile.make Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/make/windows/makefiles/compile.make Wed Jul 05 21:02:29 2017 +0200
@@ -19,7 +19,7 @@
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
-#
+#
#
# Generic compiler settings
@@ -54,7 +54,11 @@
# improving the quality of crash log stack traces involving jvm.dll.
# These are always used in all compiles
-CXX_FLAGS=$(EXTRA_CFLAGS) /nologo /W3 /WX
+CXX_FLAGS=$(EXTRA_CFLAGS) /nologo /W3
+
+!if "$(WARNINGS_AS_ERRORS)" != "false"
+CXX_FLAGS=$(CXX_FLAGS) /WX
+!endif
# Let's add debug information when Full Debug Symbols is enabled
!if "$(ENABLE_FULL_DEBUG_SYMBOLS)" == "1"
@@ -167,7 +171,7 @@
!endif
-!if $(MSC_VER) >= 1600
+!if $(MSC_VER) >= 1600
LD_FLAGS= $(LD_FLAGS) psapi.lib
!endif
@@ -191,4 +195,3 @@
!if "$(MFC_DEBUG)" == "true"
RC_FLAGS = $(RC_FLAGS) /D "_DEBUG"
!endif
-
--- a/hotspot/make/windows/makefiles/defs.make Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/make/windows/makefiles/defs.make Wed Jul 05 21:02:29 2017 +0200
@@ -31,6 +31,8 @@
SLASH_JAVA ?= J:
PATH_SEP = ;
+MAKE_ARGS += WARNINGS_AS_ERRORS=$(WARNINGS_AS_ERRORS)
+
# Need PLATFORM (os-arch combo names) for jdk and hotspot, plus libarch name
ifeq ($(ARCH_DATA_MODEL),32)
ARCH_DATA_MODEL=32
--- a/hotspot/src/cpu/ppc/vm/ppc.ad Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/ppc.ad Wed Jul 05 21:02:29 2017 +0200
@@ -5572,7 +5572,6 @@
instruct loadN2P_klass_unscaled(iRegPdst dst, memory mem) %{
match(Set dst (DecodeNKlass (LoadNKlass mem)));
- // SAPJVM GL 2014-05-21 Differs.
predicate(Universe::narrow_klass_base() == NULL && Universe::narrow_klass_shift() == 0 &&
_kids[0]->_leaf->as_Load()->is_unordered());
ins_cost(MEMORY_REF_COST);
@@ -10949,7 +10948,7 @@
// TODO: PPC port $archOpcode(ppc64Opcode_compound);
__ compiler_fast_lock_object($crx$$CondRegister, $oop$$Register, $box$$Register,
$tmp3$$Register, $tmp1$$Register, $tmp2$$Register,
- UseBiasedLocking && !UseOptoBiasInlining); // SAPJVM MD 2014-11-06 UseOptoBiasInlining
+ UseBiasedLocking && !UseOptoBiasInlining);
// If locking was successfull, crx should indicate 'EQ'.
// The compiler generates a branch to the runtime call to
// _complete_monitor_locking_Java for the case where crx is 'NE'.
--- a/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -61,7 +61,7 @@
nativeMovConstReg_at(addr())->set_narrow_oop(no, code());
}
} else {
- assert((address) (nativeMovConstReg_at(addr())->data()) == x, "data must match");
+ guarantee((address) (nativeMovConstReg_at(addr())->data()) == x, "data must match");
}
}
--- a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -60,7 +60,7 @@
masm.patchable_sethi(x, destreg);
int len = buffer - masm.pc();
for (int i = 0; i < len; i++) {
- assert(instaddr[i] == buffer[i], "instructions must match");
+ guarantee(instaddr[i] == buffer[i], "instructions must match");
}
}
--- a/hotspot/src/cpu/sparc/vm/relocInfo_sparc.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/cpu/sparc/vm/relocInfo_sparc.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -84,7 +84,7 @@
inst &= ~Assembler::simm( -1, 13);
inst |= Assembler::simm(simm13, 13);
if (verify_only) {
- assert(ip->long_at(0) == inst, "instructions must match");
+ guarantee(ip->long_at(0) == inst, "instructions must match");
} else {
ip->set_long_at(0, inst);
}
@@ -102,15 +102,15 @@
inst &= ~Assembler::hi22(-1);
inst |= Assembler::hi22((intptr_t)np);
if (verify_only) {
- assert(ip->long_at(0) == inst, "instructions must match");
+ guarantee(ip->long_at(0) == inst, "instructions must match");
} else {
ip->set_long_at(0, inst);
}
inst2 = ip->long_at( NativeInstruction::nop_instruction_size );
guarantee(Assembler::inv_op(inst2)==Assembler::arith_op, "arith op");
if (verify_only) {
- assert(ip->long_at(NativeInstruction::nop_instruction_size) == NativeInstruction::set_data32_simm13( inst2, (intptr_t)np),
- "instructions must match");
+ guarantee(ip->long_at(NativeInstruction::nop_instruction_size) == NativeInstruction::set_data32_simm13( inst2, (intptr_t)np),
+ "instructions must match");
} else {
ip->set_long_at(NativeInstruction::nop_instruction_size, NativeInstruction::set_data32_simm13( inst2, (intptr_t)np));
}
@@ -127,7 +127,7 @@
inst |= Assembler::hi22((intptr_t)x);
// (ignore offset; it doesn't play into the sethi)
if (verify_only) {
- assert(ip->long_at(0) == inst, "instructions must match");
+ guarantee(ip->long_at(0) == inst, "instructions must match");
} else {
ip->set_long_at(0, inst);
}
--- a/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -41,7 +41,7 @@
which == Assembler::imm_operand, "format unpacks ok");
if (which == Assembler::imm_operand) {
if (verify_only) {
- assert(*pd_address_in_code() == x, "instructions must match");
+ guarantee(*pd_address_in_code() == x, "instructions must match");
} else {
*pd_address_in_code() = x;
}
@@ -50,13 +50,13 @@
// both compressed oops and compressed classes look the same
if (Universe::heap()->is_in_reserved((oop)x)) {
if (verify_only) {
- assert(*(uint32_t*) disp == oopDesc::encode_heap_oop((oop)x), "instructions must match");
+ guarantee(*(uint32_t*) disp == oopDesc::encode_heap_oop((oop)x), "instructions must match");
} else {
*(int32_t*) disp = oopDesc::encode_heap_oop((oop)x);
}
} else {
if (verify_only) {
- assert(*(uint32_t*) disp == Klass::encode_klass((Klass*)x), "instructions must match");
+ guarantee(*(uint32_t*) disp == Klass::encode_klass((Klass*)x), "instructions must match");
} else {
*(int32_t*) disp = Klass::encode_klass((Klass*)x);
}
@@ -67,14 +67,14 @@
address disp = Assembler::locate_operand(ip, which);
address next_ip = Assembler::locate_next_instruction(ip);
if (verify_only) {
- assert(*(int32_t*) disp == (x - next_ip), "instructions must match");
+ guarantee(*(int32_t*) disp == (x - next_ip), "instructions must match");
} else {
*(int32_t*) disp = x - next_ip;
}
}
#else
if (verify_only) {
- assert(*pd_address_in_code() == (x + o), "instructions must match");
+ guarantee(*pd_address_in_code() == (x + o), "instructions must match");
} else {
*pd_address_in_code() = x + o;
}
--- a/hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -147,7 +147,7 @@
b_pow_x_table[0] = b;
for (int k = 0; k < D; ++k) {
// If "a" has non-zero coefficient at x**k,/ add ((b * x**k) mod P) to the result.
- if ((a & (uint64_t)(1 << (D - 1 - k))) != 0) product ^= b_pow_x_table[k];
+ if ((a & (((uint32_t)1) << (D - 1 - k))) != 0) product ^= b_pow_x_table[k];
// Compute b_pow_x_table[k+1] = (b ** x**(k+1)) mod P.
if (b_pow_x_table[k] & 1) {
--- a/hotspot/src/cpu/x86/vm/templateTable_x86.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -1611,7 +1611,7 @@
void TemplateTable::fneg() {
transition(ftos, ftos);
if (UseSSE >= 1) {
- static jlong *float_signflip = double_quadword(&float_signflip_pool[1], 0x8000000080000000, 0x8000000080000000);
+ static jlong *float_signflip = double_quadword(&float_signflip_pool[1], CONST64(0x8000000080000000), CONST64(0x8000000080000000));
__ xorps(xmm0, ExternalAddress((address) float_signflip));
} else {
LP64_ONLY(ShouldNotReachHere());
@@ -1622,7 +1622,8 @@
void TemplateTable::dneg() {
transition(dtos, dtos);
if (UseSSE >= 2) {
- static jlong *double_signflip = double_quadword(&double_signflip_pool[1], 0x8000000000000000, 0x8000000000000000);
+ static jlong *double_signflip =
+ double_quadword(&double_signflip_pool[1], CONST64(0x8000000000000000), CONST64(0x8000000000000000));
__ xorpd(xmm0, ExternalAddress((address) double_signflip));
} else {
#ifdef _LP64
--- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -652,7 +652,7 @@
result = _cpuid_info.std_cpuid1_ebx.bits.threads_per_cpu /
cores_per_cpu();
}
- return result;
+ return (result == 0 ? 1 : result);
}
static intx L1_line_size() {
--- a/hotspot/src/cpu/zero/vm/vm_version_zero.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/cpu/zero/vm/vm_version_zero.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -37,5 +37,9 @@
warning("Unaligned memory access is not available on this CPU");
FLAG_SET_DEFAULT(UseUnalignedAccesses, false);
}
+ // Disable prefetching for Zero
+ if (! FLAG_IS_DEFAULT(AllocatePrefetchDistance)) {
+ warning("Prefetching is not available for a Zero VM");
+ }
FLAG_SET_DEFAULT(AllocatePrefetchDistance, 0);
}
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java Wed Jul 05 21:02:29 2017 +0200
@@ -1112,7 +1112,7 @@
@HotSpotVMField(name = "JavaThread::_osthread", type = "OSThread*", get = HotSpotVMField.Type.OFFSET) @Stable public int osThreadOffset;
@HotSpotVMField(name = "JavaThread::_dirty_card_queue", type = "DirtyCardQueue", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadDirtyCardQueueOffset;
@HotSpotVMField(name = "JavaThread::_is_method_handle_return", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int threadIsMethodHandleReturnOffset;
- @HotSpotVMField(name = "JavaThread::_satb_mark_queue", type = "ObjPtrQueue", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadSatbMarkQueueOffset;
+ @HotSpotVMField(name = "JavaThread::_satb_mark_queue", type = "SATBMarkQueue", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadSatbMarkQueueOffset;
@HotSpotVMField(name = "JavaThread::_vm_result", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int threadObjectResultOffset;
@HotSpotVMField(name = "JavaThread::_jvmci_counters", type = "jlong*", get = HotSpotVMField.Type.OFFSET) @Stable public int jvmciCountersThreadOffset;
--- a/hotspot/src/os/aix/vm/jvm_aix.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/aix/vm/jvm_aix.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012, 2013 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -48,7 +48,6 @@
: handler;
switch (sig) {
/* The following are already used by the VM. */
- case INTERRUPT_SIGNAL:
case SIGFPE:
case SIGILL:
case SIGSEGV:
--- a/hotspot/src/os/aix/vm/jvm_aix.h Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/aix/vm/jvm_aix.h Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012, 2013 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -113,7 +113,6 @@
/* Signal definitions */
#define BREAK_SIGNAL SIGQUIT /* Thread dumping support. */
-#define INTERRUPT_SIGNAL SIGUSR1 /* Interruptible I/O support. */
#define SHUTDOWN1_SIGNAL SIGHUP /* Shutdown Hooks support. */
#define SHUTDOWN2_SIGNAL SIGINT
#define SHUTDOWN3_SIGNAL SIGTERM
--- a/hotspot/src/os/aix/vm/loadlib_aix.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/aix/vm/loadlib_aix.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -33,153 +33,337 @@
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
-// 'allocation.inline.hpp' triggers the inclusion of 'inttypes.h' which defines macros
-// required by the definitions in 'globalDefinitions.hpp'. But these macros in 'inttypes.h'
-// are only defined if '__STDC_FORMAT_MACROS' is defined!
-#include "memory/allocation.inline.hpp"
-#include "oops/oop.inline.hpp"
-#include "runtime/threadCritical.hpp"
+
+#include "loadlib_aix.hpp"
+// for CritSect
+#include "misc_aix.hpp"
+#include "porting_aix.hpp"
#include "utilities/debug.hpp"
#include "utilities/ostream.hpp"
-#include "loadlib_aix.hpp"
-#include "porting_aix.hpp"
// For loadquery()
#include <sys/ldr.h>
-///////////////////////////////////////////////////////////////////////////////
-// Implementation for LoadedLibraryModule
+// Use raw malloc instead of os::malloc - this code gets used for error reporting.
+
+// A class to "intern" eternal strings.
+// TODO: similar coding exists in AIX version of dladdr and potentially elsewhere: consolidate!
+class StringList {
+
+ char** _list;
+ int _cap;
+ int _num;
+
+ // Enlarge list. If oom, leave old list intact and return false.
+ bool enlarge() {
+ int cap2 = _cap + 64;
+ char** l2 = (char**) ::realloc(_list, sizeof(char*) * cap2);
+ if (!l2) {
+ return false;
+ }
+ _list = l2;
+ _cap = cap2;
+ return true;
+ }
+
+ // Append string to end of list.
+ // Returns NULL if oom.
+ char* append(const char* s) {
+ if (_cap == _num) {
+ if (!enlarge()) {
+ return NULL;
+ }
+ }
+ assert0(_cap > _num);
+ char* s2 = ::strdup(s);
+ if (!s2) {
+ return NULL;
+ }
+ _list[_num] = s2;
+ trcVerbose("StringDir: added %s at pos %d", s2, _num);
+ _num ++;
+ return s2;
+ }
+
+public:
-// output debug info
-void LoadedLibraryModule::print(outputStream* os) const {
- os->print("%15.15s: text: " INTPTR_FORMAT " - " INTPTR_FORMAT
- ", data: " INTPTR_FORMAT " - " INTPTR_FORMAT " ",
- shortname, text_from, text_to, data_from, data_to);
- os->print(" %s", fullpath);
- if (strlen(membername) > 0) {
- os->print("(%s)", membername);
+ StringList()
+ : _list(NULL)
+ , _cap(0)
+ , _num(0)
+ {}
+
+ // String is copied into the list; pointer to copy is returned.
+ // Returns NULL if oom.
+ char* add (const char* s) {
+ for (int i = 0; i < _num; i++) {
+ if (strcmp(_list[i], s) == 0) {
+ return _list[i];
+ }
+ }
+ return append(s);
}
- os->cr();
+
+};
+
+static StringList g_stringlist;
+
+//////////////////////
+
+// Entries are kept in a linked list ordered by text address. Entries are not
+// eternal - this list is rebuilt on every reload.
+// Note that we do not hand out those entries, but copies of them.
+
+struct entry_t {
+ entry_t* next;
+ loaded_module_t info;
+};
+
+static void print_entry(const entry_t* e, outputStream* os) {
+ const loaded_module_t* const lm = &(e->info);
+ os->print(" %c text: " INTPTR_FORMAT " - " INTPTR_FORMAT
+ ", data: " INTPTR_FORMAT " - " INTPTR_FORMAT " "
+ "%s",
+ (lm->is_in_vm ? '*' : ' '),
+ lm->text, (uintptr_t)lm->text + lm->text_len,
+ lm->data, (uintptr_t)lm->data + lm->data_len,
+ lm->path);
+ if (lm->member) {
+ os->print("(%s)", lm->member);
+ }
}
-
-///////////////////////////////////////////////////////////////////////////////
-// Implementation for LoadedLibraries
-
-// class variables
-LoadedLibraryModule LoadedLibraries::tab[MAX_MODULES];
-int LoadedLibraries::num_loaded = 0;
+static entry_t* g_first = NULL;
-// Checks whether the address p points to any of the loaded code segments.
-// If it does, returns the LoadedLibraryModule entry. If not, returns NULL.
-// static
-const LoadedLibraryModule* LoadedLibraries::find_for_text_address(const unsigned char* p) {
-
- if (num_loaded == 0) {
- reload();
- }
- for (int i = 0; i < num_loaded; i++) {
- if (tab[i].is_in_text(p)) {
- return &tab[i];
+static entry_t* find_entry_for_text_address(const void* p) {
+ for (entry_t* e = g_first; e; e = e->next) {
+ if ((uintptr_t)p >= (uintptr_t)e->info.text &&
+ (uintptr_t)p < ((uintptr_t)e->info.text + e->info.text_len)) {
+ return e;
}
}
return NULL;
}
-// Checks whether the address p points to any of the loaded data segments.
-// If it does, returns the LoadedLibraryModule entry. If not, returns NULL.
-// static
-const LoadedLibraryModule* LoadedLibraries::find_for_data_address(const unsigned char* p) {
- if (num_loaded == 0) {
- reload();
- }
- for (int i = 0; i < num_loaded; i++) {
- if (tab[i].is_in_data(p)) {
- return &tab[i];
+static entry_t* find_entry_for_data_address(const void* p) {
+ for (entry_t* e = g_first; e; e = e->next) {
+ if ((uintptr_t)p >= (uintptr_t)e->info.data &&
+ (uintptr_t)p < ((uintptr_t)e->info.data + e->info.data_len)) {
+ return e;
}
}
return NULL;
}
-// Rebuild the internal table of LoadedLibraryModule objects
-// static
-void LoadedLibraries::reload() {
-
- ThreadCritical cs;
-
- // discard old content
- num_loaded = 0;
-
- // Call loadquery(L_GETINFO..) to get a list of all loaded Dlls from AIX.
- size_t buf_size = 4096;
- char* loadquery_buf = AllocateHeap(buf_size, mtInternal);
+// Adds a new entry to the list (ordered by text address ascending).
+static void add_entry_to_list(entry_t* e, entry_t** start) {
+ entry_t* last = NULL;
+ entry_t* e2 = *start;
+ while (e2 && e2->info.text < e->info.text) {
+ last = e2;
+ e2 = e2->next;
+ }
+ if (last) {
+ last->next = e;
+ } else {
+ *start = e;
+ }
+ e->next = e2;
+}
- while(loadquery(L_GETINFO, loadquery_buf, buf_size) == -1) {
- if (errno == ENOMEM) {
- buf_size *= 2;
- loadquery_buf = ReallocateHeap(loadquery_buf, buf_size, mtInternal);
- } else {
- FreeHeap(loadquery_buf);
- // Ensure that the uintptr_t pointer is valid
- assert(errno != EFAULT, "loadquery: Invalid uintptr_t in info buffer.");
- fprintf(stderr, "loadquery failed (%d %s)", errno, strerror(errno));
- return;
- }
+static void free_entry_list(entry_t** start) {
+ entry_t* e = *start;
+ while (e) {
+ entry_t* const e2 = e->next;
+ ::free(e);
+ e = e2;
}
-
- // Iterate over the loadquery result. For details see sys/ldr.h on AIX.
- const struct ld_info* p = (struct ld_info*) loadquery_buf;
+ *start = NULL;
+}
- // Ensure we have all loaded libs.
- bool all_loaded = false;
- while(num_loaded < MAX_MODULES) {
- LoadedLibraryModule& mod = tab[num_loaded];
- mod.text_from = (const unsigned char*) p->ldinfo_textorg;
- mod.text_to = (const unsigned char*) (((char*)p->ldinfo_textorg) + p->ldinfo_textsize);
- mod.data_from = (const unsigned char*) p->ldinfo_dataorg;
- mod.data_to = (const unsigned char*) (((char*)p->ldinfo_dataorg) + p->ldinfo_datasize);
- sprintf(mod.fullpath, "%.*s", sizeof(mod.fullpath), p->ldinfo_filename);
- // do we have a member name as well (see ldr.h)?
- const char* p_mbr_name = p->ldinfo_filename + strlen(p->ldinfo_filename) + 1;
- if (*p_mbr_name) {
- sprintf(mod.membername, "%.*s", sizeof(mod.membername), p_mbr_name);
+
+// Rebuild the internal module table. If an error occurs, old table remains
+// unchanged.
+static bool reload_table() {
+
+ bool rc = false;
+
+ trcVerbose("reload module table...");
+
+ entry_t* new_list = NULL;
+ const struct ld_info* ldi = NULL;
+
+ // Call loadquery(L_GETINFO..) to get a list of all loaded Dlls from AIX. loadquery
+ // requires a large enough buffer.
+ uint8_t* buffer = NULL;
+ size_t buflen = 1024;
+ for (;;) {
+ buffer = (uint8_t*) ::realloc(buffer, buflen);
+ if (loadquery(L_GETINFO, buffer, buflen) == -1) {
+ if (errno == ENOMEM) {
+ buflen *= 2;
+ } else {
+ trcVerbose("loadquery failed (%d)", errno);
+ goto cleanup;
+ }
} else {
- mod.membername[0] = '\0';
- }
-
- // fill in the short name
- const char* p_slash = strrchr(mod.fullpath, '/');
- if (p_slash) {
- sprintf(mod.shortname, "%.*s", sizeof(mod.shortname), p_slash + 1);
- } else {
- sprintf(mod.shortname, "%.*s", sizeof(mod.shortname), mod.fullpath);
- }
- num_loaded ++;
-
- // next entry...
- if (p->ldinfo_next) {
- p = (struct ld_info*)(((char*)p) + p->ldinfo_next);
- } else {
- all_loaded = true;
break;
}
}
- FreeHeap(loadquery_buf);
+ trcVerbose("loadquery buffer size is %llu.", buflen);
+
+ // Iterate over the loadquery result. For details see sys/ldr.h on AIX.
+ ldi = (struct ld_info*) buffer;
+
+ for (;;) {
+
+ entry_t* e = (entry_t*) ::malloc(sizeof(entry_t));
+ if (!e) {
+ trcVerbose("OOM.");
+ goto cleanup;
+ }
+
+ memset(e, 0, sizeof(entry_t));
+
+ e->info.text = ldi->ldinfo_textorg;
+ e->info.text_len = ldi->ldinfo_textsize;
+ e->info.data = ldi->ldinfo_dataorg;
+ e->info.data_len = ldi->ldinfo_datasize;
+
+ e->info.path = g_stringlist.add(ldi->ldinfo_filename);
+ if (!e->info.path) {
+ trcVerbose("OOM.");
+ goto cleanup;
+ }
+
+ // Extract short name
+ {
+ const char* p = strrchr(e->info.path, '/');
+ if (p) {
+ p ++;
+ e->info.shortname = p;
+ } else {
+ e->info.shortname = e->info.path;
+ }
+ }
- // Ensure we have all loaded libs
- assert(all_loaded, "loadquery returned more entries then expected. Please increase MAX_MODULES");
+ // Do we have a member name as well (see ldr.h)?
+ const char* p_mbr_name =
+ ldi->ldinfo_filename + strlen(ldi->ldinfo_filename) + 1;
+ if (*p_mbr_name) {
+ e->info.member = g_stringlist.add(p_mbr_name);
+ if (!e->info.member) {
+ trcVerbose("OOM.");
+ goto cleanup;
+ }
+ } else {
+ e->info.member = NULL;
+ }
+
+ if (strcmp(e->info.shortname, "libjvm.so") == 0) {
+ // Note that this, theoretically, is fuzzy. We may accidentally contain
+ // more than one libjvm.so. But that is improbable, so lets go with this
+ // solution.
+ e->info.is_in_vm = true;
+ }
+
+ trcVerbose("entry: %p %llu, %p %llu, %s %s %s, %d",
+ e->info.text, e->info.text_len,
+ e->info.data, e->info.data_len,
+ e->info.path, e->info.shortname,
+ (e->info.member ? e->info.member : "NULL"),
+ e->info.is_in_vm
+ );
+
+ // Add to list.
+ add_entry_to_list(e, &new_list);
+
+ // Next entry...
+ if (ldi->ldinfo_next) {
+ ldi = (struct ld_info*)(((char*)ldi) + ldi->ldinfo_next);
+ } else {
+ break;
+ }
+ }
+
+ // We are done. All is well. Free old list and swap to new one.
+ if (g_first) {
+ free_entry_list(&g_first);
+ }
+ g_first = new_list;
+ new_list = NULL;
+
+ rc = true;
+
+cleanup:
+
+ if (new_list) {
+ free_entry_list(&new_list);
+ }
+
+ ::free(buffer);
+
+ return rc;
} // end LoadedLibraries::reload()
-// output loaded libraries table
-//static
-void LoadedLibraries::print(outputStream* os) {
+///////////////////////////////////////////////////////////////////////////////
+// Externals
+
+static MiscUtils::CritSect g_cs;
- for (int i = 0; i < num_loaded; i++) {
- tab[i].print(os);
+// Rebuild the internal module table. If an error occurs, old table remains
+// unchanged.
+bool LoadedLibraries::reload() {
+ MiscUtils::AutoCritSect lck(&g_cs);
+ return reload_table();
+}
+
+void LoadedLibraries::print(outputStream* os) {
+ MiscUtils::AutoCritSect lck(&g_cs);
+ if (!g_first) {
+ reload_table();
}
-
+ for (entry_t* e = g_first; e; e = e->next) {
+ print_entry(e, os);
+ os->cr();
+ }
}
+bool LoadedLibraries::find_for_text_address(const void* p,
+ loaded_module_t* info) {
+ MiscUtils::AutoCritSect lck(&g_cs);
+ if (!g_first) {
+ reload_table();
+ }
+ const entry_t* const e = find_entry_for_text_address(p);
+ if (e) {
+ if (info) {
+ *info = e->info;
+ }
+ return true;
+ }
+ return false;
+}
+
+
+bool LoadedLibraries::find_for_data_address (
+ const void* p,
+ loaded_module_t* info // optional. can be NULL:
+) {
+ MiscUtils::AutoCritSect lck(&g_cs);
+ if (!g_first) {
+ reload_table();
+ }
+ const entry_t* const e = find_entry_for_data_address(p);
+ if (e) {
+ if (info) {
+ *info = e->info;
+ }
+ return true;
+ }
+ return false;
+}
+
--- a/hotspot/src/os/aix/vm/loadlib_aix.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/aix/vm/loadlib_aix.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -26,73 +26,47 @@
// Loadlib_aix.cpp contains support code for analysing the memory
// layout of loaded binaries in ones own process space.
//
-// It is needed, among other things, to provide a dladdr() emulation, because
-// that one is not provided by AIX
+// It is needed, among other things, to provide dladdr(3), which is
+// missing on AIX.
#ifndef OS_AIX_VM_LOADLIB_AIX_HPP
#define OS_AIX_VM_LOADLIB_AIX_HPP
+#include <stddef.h>
+
class outputStream;
-// This class holds information about a single loaded library module.
+// Struct holds information about a single loaded library module.
// Note that on AIX, a single library can be spread over multiple
-// uintptr_t range on a module base, eg.
+// uintptr_t ranges on a module base, eg.
// libC.a(shr3_64.o) or libC.a(shrcore_64.o).
-class LoadedLibraryModule {
-
- friend class LoadedLibraries;
- char fullpath[512]; // eg /usr/lib/libC.a
- char shortname[30]; // eg libC.a
- char membername[30]; // eg shrcore_64.o
- const unsigned char* text_from;
- const unsigned char* text_to;
- const unsigned char* data_from;
- const unsigned char* data_to;
-
- public:
+// Note: all pointers to strings (path, member) point to strings which are immortal.
+struct loaded_module_t {
- const char* get_fullpath() const {
- return fullpath;
- }
- const char* get_shortname() const {
- return shortname;
- }
- const char* get_membername() const {
- return membername;
- }
+ // Points to the full path of the lodaed module, e.g.
+ // "/usr/lib/libC.a".
+ const char* path;
+
+ // Host library name without path
+ const char* shortname;
- // text_from, text_to: returns the range of the text (code)
- // segment for that module
- const unsigned char* get_text_from() const {
- return text_from;
- }
- const unsigned char* get_text_to() const {
- return text_to;
- }
+ // Points to the object file (AIX specific stuff)
+ // e.g "shrcore_64.o".
+ const char* member;
+
+ // Text area from, to
+ const void* text;
+ size_t text_len;
- // data_from/data_to: returns the range of the data
- // segment for that module
- const unsigned char* get_data_from() const {
- return data_from;
- }
- const unsigned char* get_data_to() const {
- return data_to;
- }
+ // Data area from, to
+ const void* data;
+ size_t data_len;
- // returns true if the
- bool is_in_text(const unsigned char* p) const {
- return p >= text_from && p < text_to ? true : false;
- }
+ // True if this module is part of the vm.
+ bool is_in_vm;
- bool is_in_data(const unsigned char* p) const {
- return p >= data_from && p < data_to ? true : false;
- }
-
- // output debug info
- void print(outputStream* os) const;
-
-}; // end LoadedLibraryModule
+};
// This class is a singleton holding a map of all loaded binaries
// in the AIX process space.
@@ -100,29 +74,31 @@
// : AllStatic (including allocation.hpp just for AllStatic is overkill.)
{
- private:
-
- enum {MAX_MODULES = 100};
- static LoadedLibraryModule tab[MAX_MODULES];
- static int num_loaded;
-
public:
- // rebuild the internal table of LoadedLibraryModule objects
- static void reload();
+ // Rebuild the internal module table. If an error occurs, internal module
+ // table remains untouched.
+ static bool reload();
- // checks whether the address p points to any of the loaded code segments.
- // If it does, returns the LoadedLibraryModule entry. If not, returns NULL.
- static const LoadedLibraryModule* find_for_text_address(const unsigned char* p);
+ // Check whether the given address points into the text segment of a
+ // loaded module. Return true if this is the case.
+ // Optionally, information about the module is returned (info)
+ static bool find_for_text_address (
+ const void* p,
+ loaded_module_t* info // Optional, leave NULL if not needed.
+ );
- // checks whether the address p points to any of the loaded data segments.
- // If it does, returns the LoadedLibraryModule entry. If not, returns NULL.
- static const LoadedLibraryModule* find_for_data_address(const unsigned char* p);
+ // Check whether the given address points into the data segment of a
+ // loaded module. Return true if this is the case.
+ // Optionally, information about the module is returned (info)
+ static bool find_for_data_address (
+ const void* p,
+ loaded_module_t* info // Optional, leave NULL if not needed.
+ );
- // output debug info
+ // Output debug info
static void print(outputStream* os);
-}; // end LoadedLibraries
-
+};
#endif // OS_AIX_VM_LOADLIB_AIX_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/os/aix/vm/misc_aix.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015 SAP AG. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "misc_aix.hpp"
+#include "runtime/stubRoutines.hpp"
+
+#include <pthread.h>
+
+void MiscUtils::init_critsect(MiscUtils::critsect_t* cs) {
+ const int rc = pthread_mutex_init(cs, NULL);
+ assert0(rc == 0);
+}
+
+void MiscUtils::free_critsect(MiscUtils::critsect_t* cs) {
+ const int rc = pthread_mutex_destroy(cs);
+ assert0(rc == 0);
+}
+
+void MiscUtils::enter_critsect(MiscUtils::critsect_t* cs) {
+ const int rc = pthread_mutex_lock(cs);
+ assert0(rc == 0);
+}
+
+void MiscUtils::leave_critsect(MiscUtils::critsect_t* cs) {
+ const int rc = pthread_mutex_unlock(cs);
+ assert0(rc == 0);
+}
+
+bool MiscUtils::is_readable_pointer(const void* p) {
+ if (!CanUseSafeFetch32()) {
+ return true;
+ }
+ int* const aligned = (int*) align_size_down((intptr_t)p, 4);
+ int cafebabe = 0xcafebabe;
+ int deadbeef = 0xdeadbeef;
+ return (SafeFetch32(aligned, cafebabe) != cafebabe) ||
+ (SafeFetch32(aligned, deadbeef) != deadbeef);
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/os/aix/vm/misc_aix.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2012, 2015 SAP AG. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+
+#ifndef OS_AIX_VM_MISC_AIX_HPP
+#define OS_AIX_VM_MISC_AIX_HPP
+
+// misc_aix.hpp, misc_aix.cpp: convenience functions needed for the OpenJDK AIX
+// port.
+#include "utilities/globalDefinitions.hpp"
+
+#include <pthread.h>
+
+// Trace if verbose to tty.
+#define trcVerbose(fmt, ...) { \
+ if (Verbose) { \
+ fprintf(stderr, fmt, ##__VA_ARGS__); \
+ fputc('\n', stderr); fflush(stderr); \
+ } \
+}
+#define ERRBYE(s) { trcVerbose(s); return -1; }
+#define trc(fmt, ...)
+
+#define assert0(b) assert((b), "")
+#define guarantee0(b) guarantee((b), "")
+template <class T1, class T2> bool is_aligned_to(T1 what, T2 alignment) {
+ return (((uintx)(what)) & (((uintx)(alignment)) - 1)) == 0 ? true : false;
+}
+
+// CritSect: simple critical section implementation using pthread mutexes.
+namespace MiscUtils {
+ typedef pthread_mutex_t critsect_t;
+
+ void init_critsect(MiscUtils::critsect_t* cs);
+ void free_critsect(MiscUtils::critsect_t* cs);
+ void enter_critsect(MiscUtils::critsect_t* cs);
+ void leave_critsect(MiscUtils::critsect_t* cs);
+
+ // Need to wrap this in an object because we need to dynamically initialize
+ // critical section (because of windows, where there is no way to initialize
+ // a CRITICAL_SECTION statically. On Unix, we could use
+ // PTHREAD_MUTEX_INITIALIZER).
+
+ // Note: The critical section does NOT get cleaned up in the destructor. That is
+ // by design: the CritSect class is only ever used as global objects whose
+ // lifetime spans the whole VM life; in that context we don't want the lock to
+ // be cleaned up when global C++ objects are destroyed, but to continue to work
+ // correctly right to the very end of the process life.
+ class CritSect {
+ critsect_t _cs;
+ public:
+ CritSect() { init_critsect(&_cs); }
+ //~CritSect() { free_critsect(&_cs); }
+ void enter() { enter_critsect(&_cs); }
+ void leave() { leave_critsect(&_cs); }
+ };
+
+ class AutoCritSect {
+ CritSect* const _pcsobj;
+ public:
+ AutoCritSect(CritSect* pcsobj)
+ : _pcsobj(pcsobj)
+ {
+ _pcsobj->enter();
+ }
+ ~AutoCritSect() {
+ _pcsobj->leave();
+ }
+ };
+
+ // Returns true if pointer can be dereferenced without triggering a segment
+ // violation. Returns false if pointer is invalid.
+ // Note: Depends on stub routines; prior to stub routine generation, will
+ // always return true. Use CanUseSafeFetch32 to handle this case.
+ bool is_readable_pointer(const void* p);
+
+}
+
+#endif // OS_AIX_VM_MISC_AIX_HPP
+
--- a/hotspot/src/os/aix/vm/os_aix.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/aix/vm/os_aix.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -40,6 +40,7 @@
#include "loadlib_aix.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/filemap.hpp"
+#include "misc_aix.hpp"
#include "mutex_aix.inline.hpp"
#include "oops/oop.inline.hpp"
#include "os_aix.inline.hpp"
@@ -159,23 +160,10 @@
#define PV_8_Compat 0x308000 /* Power PC 8 */
#endif
-#define trcVerbose(fmt, ...) { /* PPC port */ \
- if (Verbose) { \
- fprintf(stderr, fmt, ##__VA_ARGS__); \
- fputc('\n', stderr); fflush(stderr); \
- } \
-}
-#define trc(fmt, ...) /* PPC port */
-
-#define ERRBYE(s) { \
- trcVerbose(s); \
- return -1; \
-}
-
// Query dimensions of the stack of the calling thread.
static bool query_stack_dimensions(address* p_stack_base, size_t* p_stack_size);
-// function to check a given stack pointer against given stack limits
+// Function to check a given stack pointer against given stack limits.
inline bool is_valid_stackpointer(stackptr_t sp, stackptr_t stack_base, size_t stack_size) {
if (((uintptr_t)sp) & 0x7) {
return false;
@@ -189,7 +177,7 @@
return true;
}
-// returns true if function is a valid codepointer
+// Returns true if function is a valid codepointer.
inline bool is_valid_codepointer(codeptr_t p) {
if (!p) {
return false;
@@ -197,7 +185,7 @@
if (((uintptr_t)p) & 0x3) {
return false;
}
- if (LoadedLibraries::find_for_text_address((address)p) == NULL) {
+ if (!LoadedLibraries::find_for_text_address(p, NULL)) {
return false;
}
return true;
@@ -1387,26 +1375,15 @@
// Input could be a real pc or a function pointer literal. The latter
// would be a function descriptor residing in the data segment of a module.
-
- const LoadedLibraryModule* lib = LoadedLibraries::find_for_text_address(addr);
- if (lib) {
- if (strcmp(lib->get_shortname(), "libjvm.so") == 0) {
- return true;
- } else {
- return false;
- }
+ loaded_module_t lm;
+ if (LoadedLibraries::find_for_text_address(addr, &lm) != NULL) {
+ return lm.is_in_vm;
+ } else if (LoadedLibraries::find_for_data_address(addr, &lm) != NULL) {
+ return lm.is_in_vm;
} else {
- lib = LoadedLibraries::find_for_data_address(addr);
- if (lib) {
- if (strcmp(lib->get_shortname(), "libjvm.so") == 0) {
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
+ return false;
+ }
+
}
// Resolve an AIX function descriptor literal to a code pointer.
@@ -1418,21 +1395,18 @@
// NULL is returned.
static address resolve_function_descriptor_to_code_pointer(address p) {
- const LoadedLibraryModule* lib = LoadedLibraries::find_for_text_address(p);
- if (lib) {
- // its a real code pointer
+ if (LoadedLibraries::find_for_text_address(p, NULL) != NULL) {
+ // It is a real code pointer.
return p;
- } else {
- lib = LoadedLibraries::find_for_data_address(p);
- if (lib) {
- // pointer to data segment, potential function descriptor
- address code_entry = (address)(((FunctionDescriptor*)p)->entry());
- if (LoadedLibraries::find_for_text_address(code_entry)) {
- // Its a function descriptor
- return code_entry;
- }
+ } else if (LoadedLibraries::find_for_data_address(p, NULL) != NULL) {
+ // Pointer to data segment, potential function descriptor.
+ address code_entry = (address)(((FunctionDescriptor*)p)->entry());
+ if (LoadedLibraries::find_for_text_address(code_entry, NULL) != NULL) {
+ // It is a function descriptor.
+ return code_entry;
}
}
+
return NULL;
}
@@ -1461,7 +1435,6 @@
char* p_errmsg, size_t errmsglen // [out] optional: user provided buffer for error messages
) {
- // initialize output parameters
if (p_name && namelen > 0) {
*p_name = '\0';
}
@@ -1469,16 +1442,15 @@
*p_errmsg = '\0';
}
- const LoadedLibraryModule* const lib = LoadedLibraries::find_for_text_address((address)pc);
- if (lib) {
- if (p_name && namelen > 0) {
- sprintf(p_name, "%.*s", namelen, lib->get_shortname());
+ if (p_name && namelen > 0) {
+ loaded_module_t lm;
+ if (LoadedLibraries::find_for_text_address(pc, &lm) != NULL) {
+ strncpy(p_name, lm.shortname, namelen);
+ p_name[namelen - 1] = '\0';
}
return 0;
}
- trcVerbose("pc outside any module");
-
return -1;
}
@@ -1690,7 +1662,6 @@
print_signal_handler(st, SIGPIPE, buf, buflen);
print_signal_handler(st, SIGXFSZ, buf, buflen);
print_signal_handler(st, SIGILL , buf, buflen);
- print_signal_handler(st, INTERRUPT_SIGNAL, buf, buflen);
print_signal_handler(st, SR_signum, buf, buflen);
print_signal_handler(st, SHUTDOWN1_SIGNAL, buf, buflen);
print_signal_handler(st, SHUTDOWN2_SIGNAL , buf, buflen);
@@ -3309,7 +3280,6 @@
}
DO_SIGNAL_CHECK(SR_signum);
- DO_SIGNAL_CHECK(INTERRUPT_SIGNAL);
}
typedef int (*os_sigaction_t)(int, const struct sigaction *, struct sigaction *);
@@ -3351,10 +3321,6 @@
jvmHandler = (address)user_handler();
break;
- case INTERRUPT_SIGNAL:
- jvmHandler = CAST_FROM_FN_PTR(address, SIG_DFL);
- break;
-
default:
if (sig == SR_signum) {
jvmHandler = CAST_FROM_FN_PTR(address, (sa_sigaction_t)SR_handler);
@@ -3787,18 +3753,11 @@
st->print(PTR_FORMAT ": ", addr);
- const LoadedLibraryModule* lib = LoadedLibraries::find_for_text_address(addr);
- if (lib) {
- lib->print(st);
+ loaded_module_t lm;
+ if (LoadedLibraries::find_for_text_address(addr, &lm) != NULL ||
+ LoadedLibraries::find_for_data_address(addr, &lm) != NULL) {
+ st->print("%s", lm.path);
return true;
- } else {
- lib = LoadedLibraries::find_for_data_address(addr);
- if (lib) {
- lib->print(st);
- return true;
- } else {
- st->print_cr("(outside any module)");
- }
}
return false;
@@ -3965,9 +3924,6 @@
if (::fstat64(fd, &buf64) >= 0) {
mode = buf64.st_mode;
if (S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) {
- // XXX: is the following call interruptible? If so, this might
- // need to go through the INTERRUPT_IO() wrapper as for other
- // blocking, interruptible calls in this file.
int n;
if (::ioctl(fd, FIONREAD, &n) >= 0) {
*bytes = n;
--- a/hotspot/src/os/aix/vm/perfMemory_aix.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/aix/vm/perfMemory_aix.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -201,6 +201,7 @@
// the backing store files. Returns true if the directory is considered
// a secure location. Returns false if the statbuf is a symbolic link or
// if an error occurred.
+//
static bool is_statbuf_secure(struct stat *statp) {
if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) {
// The path represents a link or some non-directory file type,
@@ -209,15 +210,18 @@
return false;
}
// We have an existing directory, check if the permissions are safe.
+ //
if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) {
// The directory is open for writing and could be subjected
// to a symlink or a hard link attack. Declare it insecure.
+ //
return false;
}
- // See if the uid of the directory matches the effective uid of the process.
- //
- if (statp->st_uid != geteuid()) {
+ // If user is not root then see if the uid of the directory matches the effective uid of the process.
+ uid_t euid = geteuid();
+ if ((euid != 0) && (statp->st_uid != euid)) {
// The directory was not created by this user, declare it insecure.
+ //
return false;
}
return true;
@@ -228,6 +232,7 @@
// the backing store files. Returns true if the directory exists
// and is considered a secure location. Returns false if the path
// is a symbolic link or if an error occurred.
+//
static bool is_directory_secure(const char* path) {
struct stat statbuf;
int result = 0;
--- a/hotspot/src/os/aix/vm/porting_aix.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/aix/vm/porting_aix.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -23,11 +23,13 @@
*/
#include "asm/assembler.hpp"
+#include "loadlib_aix.hpp"
#include "memory/allocation.hpp"
#include "memory/allocation.inline.hpp"
+// For CritSect
+#include "misc_aix.hpp"
+#include "porting_aix.hpp"
#include "runtime/os.hpp"
-#include "loadlib_aix.hpp"
-#include "porting_aix.hpp"
#include "utilities/debug.hpp"
#include <demangle.h>
@@ -45,23 +47,6 @@
#define PTRDIFF_BYTES(p1,p2) (((ptrdiff_t)p1) - ((ptrdiff_t)p2))
-// Align a pointer without having to cast.
-inline char* align_ptr_up(char* ptr, intptr_t alignment) {
- return (char*) align_size_up((intptr_t)ptr, alignment);
-}
-
-// Trace if verbose to tty.
-// I use these now instead of the Xtrace system because the latter is
-// not available at init time, hence worthless. Until we fix this, all
-// tracing here is done with -XX:+Verbose.
-#define trcVerbose(fmt, ...) { \
- if (Verbose) { \
- fprintf(stderr, fmt, ##__VA_ARGS__); \
- fputc('\n', stderr); fflush(stderr); \
- } \
-}
-#define ERRBYE(s) { trcVerbose(s); return -1; }
-
// Unfortunately, the interface of dladdr makes the implementator
// responsible for maintaining memory for function name/library
// name. I guess this is because most OS's keep those values as part
@@ -139,18 +124,37 @@
ERRBYE("invalid program counter");
}
+ // We see random but frequent crashes in this function since some months mainly on shutdown
+ // (-XX:+DumpInfoAtExit). It appears the page we are reading is randomly disappearing while
+ // we read it (?).
+ // As the pc cannot be trusted to be anything sensible lets make all reads via SafeFetch. Also
+ // bail if this is not a text address right now.
+ if (!LoadedLibraries::find_for_text_address(pc, NULL)) {
+ ERRBYE("not a text address");
+ }
+
+ // .. (Note that is_readable_pointer returns true if safefetch stubs are not there yet;
+ // in that case I try reading the traceback table unsafe - I rather risk secondary crashes in
+ // error files than not having a callstack.)
+#define CHECK_POINTER_READABLE(p) \
+ if (!MiscUtils::is_readable_pointer(p)) { \
+ ERRBYE("pc not readable"); \
+ }
+
codeptr_t pc2 = pc;
- // make sure the pointer is word aligned.
+ // Make sure the pointer is word aligned.
pc2 = (codeptr_t) align_ptr_up((char*)pc2, 4);
+ CHECK_POINTER_READABLE(pc2)
// Find start of traceback table.
// (starts after code, is marked by word-aligned (32bit) zeros)
while ((*pc2 != NULL) && (searchcount++ < MAX_FUNC_SEARCH_LEN)) {
+ CHECK_POINTER_READABLE(pc2)
pc2++;
}
if (*pc2 != 0) {
- ERRBYE("could not find traceback table within 5000 bytes of program counter");
+ ERRBYE("no traceback table found");
}
//
// Set up addressability to the traceback table
@@ -162,7 +166,7 @@
if (tb->tb.lang >= 0xf && tb->tb.lang <= 0xfb) {
// Language specifiers, go from 0 (C) to 14 (Objective C).
// According to spec, 0xf-0xfa reserved, 0xfb-0xff reserved for ibm.
- ERRBYE("not a traceback table");
+ ERRBYE("no traceback table found");
}
// Existence of fields in the tbtable extension are contingent upon
@@ -173,6 +177,8 @@
if (tb->tb.fixedparms != 0 || tb->tb.floatparms != 0)
pc2++;
+ CHECK_POINTER_READABLE(pc2)
+
if (tb->tb.has_tboff == TRUE) {
// I want to know the displacement
@@ -182,7 +188,7 @@
// Weed out the cases where we did find the wrong traceback table.
if (pc < start_of_procedure) {
- ERRBYE("could not find (the real) traceback table within 5000 bytes of program counter");
+ ERRBYE("no traceback table found");
}
// return the displacement
@@ -204,15 +210,24 @@
if (tb->tb.has_ctl == TRUE)
pc2 += (*pc2) + 1; // don't care
+ CHECK_POINTER_READABLE(pc2)
+
//
// return function name if it exists.
//
if (p_name && namelen > 0) {
if (tb->tb.name_present) {
+ // Copy name from text because it may not be zero terminated.
+ // 256 is good enough for most cases; do not use large buffers here.
char buf[256];
const short l = MIN2<short>(*((short*)pc2), sizeof(buf) - 1);
- memcpy(buf, (char*)pc2 + sizeof(short), l);
- buf[l] = '\0';
+ // Be very careful.
+ int i = 0; char* const p = (char*)pc2 + sizeof(short);
+ while (i < l && MiscUtils::is_readable_pointer(p + i)) {
+ buf[i] = p[i];
+ i++;
+ }
+ buf[i] = '\0';
p_name[0] = '\0';
@@ -275,7 +290,8 @@
info->dli_saddr = NULL;
address p = (address) addr;
- const LoadedLibraryModule* lib = NULL;
+ loaded_module_t lm;
+ bool found = false;
enum { noclue, code, data } type = noclue;
@@ -284,28 +300,28 @@
// Note: input address may be a function. I accept both a pointer to
// the entry of a function and a pointer to the function decriptor.
// (see ppc64 ABI)
- lib = LoadedLibraries::find_for_text_address(p);
- if (lib) {
+ found = LoadedLibraries::find_for_text_address(p, &lm);
+ if (found) {
type = code;
}
- if (!lib) {
+ if (!found) {
// Not a pointer into any text segment. Is it a function descriptor?
const FunctionDescriptor* const pfd = (const FunctionDescriptor*) p;
p = pfd->entry();
if (p) {
- lib = LoadedLibraries::find_for_text_address(p);
- if (lib) {
+ found = LoadedLibraries::find_for_text_address(p, &lm);
+ if (found) {
type = code;
}
}
}
- if (!lib) {
+ if (!found) {
// Neither direct code pointer nor function descriptor. A data ptr?
p = (address)addr;
- lib = LoadedLibraries::find_for_data_address(p);
- if (lib) {
+ found = LoadedLibraries::find_for_data_address(p, &lm);
+ if (found) {
type = data;
}
}
@@ -313,12 +329,10 @@
// If we did find the shared library this address belongs to (either
// code or data segment) resolve library path and, if possible, the
// symbol name.
- if (lib) {
- const char* const interned_libpath =
- dladdr_fixed_strings.intern(lib->get_fullpath());
- if (interned_libpath) {
- info->dli_fname = interned_libpath;
- }
+ if (found) {
+
+ // No need to intern the libpath, that one is already interned one layer below.
+ info->dli_fname = lm.path;
if (type == code) {
@@ -328,7 +342,7 @@
int displacement = 0;
if (getFuncName((codeptr_t) p, funcname, sizeof(funcname), &displacement,
- NULL, NULL, 0, true /* demangle */) == 0) {
+ NULL, NULL, 0, false) == 0) {
if (funcname[0] != '\0') {
const char* const interned = dladdr_fixed_strings.intern(funcname);
info->dli_sname = interned;
--- a/hotspot/src/os/aix/vm/porting_aix.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/aix/vm/porting_aix.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -27,13 +27,6 @@
#include <stddef.h>
-// PPC port only:
-#define assert0(b) assert( (b), "" )
-#define guarantee0(b) assert( (b), "" )
-template <class T1, class T2> bool is_aligned_to(T1 what, T2 alignment) {
- return ( ((uintx)(what)) & (((uintx)(alignment)) - 1) ) == 0 ? true : false;
-}
-
// Header file to contain porting-relevant code which does not have a
// home anywhere else and which can not go into os_<platform>.h because
// that header is included inside the os class definition, hence all
@@ -68,13 +61,9 @@
#endif
int dladdr(void *addr, Dl_info *info);
+typedef unsigned int* codeptr_t;
-// The semantics in this file are thus that codeptr_t is a *real code ptr*.
-// This means that any function taking codeptr_t as arguments will assume
-// a real codeptr and won't handle function descriptors (eg getFuncName),
-// whereas functions taking address as args will deal with function
-// descriptors (eg os::dll_address_to_library_name).
-typedef unsigned int* codeptr_t;
+struct tbtable;
// helper function - given a program counter, tries to locate the traceback table and
// returns info from it (like, most importantly, function name, displacement of the
@@ -87,65 +76,9 @@
char* p_name, size_t namelen, // [out] optional: user provided buffer for the function name
int* p_displacement, // [out] optional: displacement
const struct tbtable** p_tb, // [out] optional: ptr to traceback table to get further information
- char* p_errmsg, size_t errmsglen,// [out] optional: user provided buffer for error messages
- bool demangle = true // [in] whether to demangle the name
+ char* p_errmsg, size_t errmsglen, // [out] optional: user provided buffer for error messages
+ bool demangle // [in] whether to demangle the name
);
-// -------------------------------------------------------------------------
-
-// A simple critical section which shall be based upon OS critical
-// sections (CRITICAL_SECTION resp. Posix Mutex) and nothing else.
-
-#include <pthread.h>
-
-namespace MiscUtils {
- typedef pthread_mutex_t critsect_t;
-
- inline void init_critsect(MiscUtils::critsect_t* cs) {
- pthread_mutex_init(cs, NULL);
- }
- inline void free_critsect(MiscUtils::critsect_t* cs) {
- pthread_mutex_destroy(cs);
- }
- inline void enter_critsect(MiscUtils::critsect_t* cs) {
- pthread_mutex_lock(cs);
- }
- inline void leave_critsect(MiscUtils::critsect_t* cs) {
- pthread_mutex_unlock(cs);
- }
-
- // Need to wrap this in an object because we need to dynamically initialize
- // critical section (because of windows, where there is no way to initialize
- // a CRITICAL_SECTION statically. On Unix, we could use
- // PTHREAD_MUTEX_INITIALIZER)
+#endif // OS_AIX_VM_PORTING_AIX_HPP
- // Note: The critical section does NOT get cleaned up in the destructor. That is
- // by design: the CritSect class is only ever used as global objects whose
- // lifetime spans the whole VM life; in that context we don't want the lock to
- // be cleaned up when global C++ objects are destroyed, but to continue to work
- // correctly right to the very end of the process life.
- class CritSect {
- critsect_t _cs;
- public:
- CritSect() { init_critsect(&_cs); }
- //~CritSect() { free_critsect(&_cs); }
- void enter() { enter_critsect(&_cs); }
- void leave() { leave_critsect(&_cs); }
- };
-
- class AutoCritSect {
- CritSect* const _pcsobj;
- public:
- AutoCritSect(CritSect* pcsobj)
- : _pcsobj(pcsobj)
- {
- _pcsobj->enter();
- }
- ~AutoCritSect() {
- _pcsobj->leave();
- }
- };
-
-}
-
-#endif // OS_AIX_VM_PORTING_AIX_HPP
--- a/hotspot/src/os/bsd/vm/jvm_bsd.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/bsd/vm/jvm_bsd.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -47,7 +47,6 @@
: handler;
switch (sig) {
/* The following are already used by the VM. */
- case INTERRUPT_SIGNAL:
case SIGFPE:
case SIGILL:
case SIGSEGV:
--- a/hotspot/src/os/bsd/vm/jvm_bsd.h Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/bsd/vm/jvm_bsd.h Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -107,7 +107,6 @@
/* Signal definitions */
#define BREAK_SIGNAL SIGQUIT /* Thread dumping support. */
-#define INTERRUPT_SIGNAL SIGUSR1 /* Interruptible I/O support. */
#define SHUTDOWN1_SIGNAL SIGHUP /* Shutdown Hooks support. */
#define SHUTDOWN2_SIGNAL SIGINT
#define SHUTDOWN3_SIGNAL SIGTERM
--- a/hotspot/src/os/bsd/vm/os_bsd.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/bsd/vm/os_bsd.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -1777,7 +1777,6 @@
print_signal_handler(st, SIGPIPE, buf, buflen);
print_signal_handler(st, SIGXFSZ, buf, buflen);
print_signal_handler(st, SIGILL , buf, buflen);
- print_signal_handler(st, INTERRUPT_SIGNAL, buf, buflen);
print_signal_handler(st, SR_signum, buf, buflen);
print_signal_handler(st, SHUTDOWN1_SIGNAL, buf, buflen);
print_signal_handler(st, SHUTDOWN2_SIGNAL , buf, buflen);
@@ -3345,7 +3344,6 @@
}
DO_SIGNAL_CHECK(SR_signum);
- DO_SIGNAL_CHECK(INTERRUPT_SIGNAL);
}
typedef int (*os_sigaction_t)(int, const struct sigaction *, struct sigaction *);
@@ -3391,10 +3389,6 @@
jvmHandler = (address)user_handler();
break;
- case INTERRUPT_SIGNAL:
- jvmHandler = CAST_FROM_FN_PTR(address, SIG_DFL);
- break;
-
default:
if (sig == SR_signum) {
jvmHandler = CAST_FROM_FN_PTR(address, (sa_sigaction_t)SR_handler);
@@ -3913,9 +3907,6 @@
if (::fstat(fd, &buf) >= 0) {
mode = buf.st_mode;
if (S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) {
- // XXX: is the following call interruptible? If so, this might
- // need to go through the INTERRUPT_IO() wrapper as for other
- // blocking, interruptible calls in this file.
int n;
if (::ioctl(fd, FIONREAD, &n) >= 0) {
*bytes = n;
--- a/hotspot/src/os/bsd/vm/perfMemory_bsd.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/bsd/vm/perfMemory_bsd.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -217,9 +217,9 @@
//
return false;
}
- // See if the uid of the directory matches the effective uid of the process.
- //
- if (statp->st_uid != geteuid()) {
+ // If user is not root then see if the uid of the directory matches the effective uid of the process.
+ uid_t euid = geteuid();
+ if ((euid != 0) && (statp->st_uid != euid)) {
// The directory was not created by this user, declare it insecure.
//
return false;
--- a/hotspot/src/os/linux/vm/attachListener_linux.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/linux/vm/attachListener_linux.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -254,6 +254,8 @@
do {
int n;
RESTARTABLE(read(s, buf+off, left), n);
+ assert(n <= left, "buffer was too small, impossible!");
+ buf[max_len - 1] = '\0';
if (n == -1) {
return NULL; // reset by peer or other error
}
--- a/hotspot/src/os/linux/vm/jvm_linux.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/linux/vm/jvm_linux.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -47,7 +47,6 @@
: handler;
switch (sig) {
/* The following are already used by the VM. */
- case INTERRUPT_SIGNAL:
case SIGFPE:
case SIGILL:
case SIGSEGV:
--- a/hotspot/src/os/linux/vm/jvm_linux.h Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/linux/vm/jvm_linux.h Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -88,7 +88,6 @@
/* Signal definitions */
#define BREAK_SIGNAL SIGQUIT /* Thread dumping support. */
-#define INTERRUPT_SIGNAL SIGUSR1 /* Interruptible I/O support. */
#define SHUTDOWN1_SIGNAL SIGHUP /* Shutdown Hooks support. */
#define SHUTDOWN2_SIGNAL SIGINT
#define SHUTDOWN3_SIGNAL SIGTERM
--- a/hotspot/src/os/linux/vm/os_linux.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -2302,7 +2302,6 @@
print_signal_handler(st, SIGPIPE, buf, buflen);
print_signal_handler(st, SIGXFSZ, buf, buflen);
print_signal_handler(st, SIGILL , buf, buflen);
- print_signal_handler(st, INTERRUPT_SIGNAL, buf, buflen);
print_signal_handler(st, SR_signum, buf, buflen);
print_signal_handler(st, SHUTDOWN1_SIGNAL, buf, buflen);
print_signal_handler(st, SHUTDOWN2_SIGNAL , buf, buflen);
@@ -2820,7 +2819,6 @@
// Something to do with the numa-aware allocator needs these symbols
extern "C" JNIEXPORT void numa_warn(int number, char *where, ...) { }
extern "C" JNIEXPORT void numa_error(char *where) { }
-extern "C" JNIEXPORT int fork1() { return fork(); }
// If we are running with libnuma version > 2, then we should
@@ -4254,7 +4252,9 @@
void os::Linux::set_our_sigflags(int sig, int flags) {
assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range");
- sigflags[sig] = flags;
+ if (sig > 0 && sig < MAXSIGNUM) {
+ sigflags[sig] = flags;
+ }
}
void os::Linux::set_signal_handler(int sig, bool set_installed) {
@@ -4496,7 +4496,6 @@
}
DO_SIGNAL_CHECK(SR_signum);
- DO_SIGNAL_CHECK(INTERRUPT_SIGNAL);
}
typedef int (*os_sigaction_t)(int, const struct sigaction *, struct sigaction *);
@@ -4542,10 +4541,6 @@
jvmHandler = (address)user_handler();
break;
- case INTERRUPT_SIGNAL:
- jvmHandler = CAST_FROM_FN_PTR(address, SIG_DFL);
- break;
-
default:
if (sig == SR_signum) {
jvmHandler = CAST_FROM_FN_PTR(address, (sa_sigaction_t)SR_handler);
@@ -5130,9 +5125,6 @@
if (::fstat64(fd, &buf64) >= 0) {
mode = buf64.st_mode;
if (S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) {
- // XXX: is the following call interruptible? If so, this might
- // need to go through the INTERRUPT_IO() wrapper as for other
- // blocking, interruptible calls in this file.
int n;
if (::ioctl(fd, FIONREAD, &n) >= 0) {
*bytes = n;
@@ -5937,23 +5929,21 @@
char core_pattern[core_pattern_len] = {0};
int core_pattern_file = ::open("/proc/sys/kernel/core_pattern", O_RDONLY);
- if (core_pattern_file != -1) {
- ssize_t ret = ::read(core_pattern_file, core_pattern, core_pattern_len);
- ::close(core_pattern_file);
-
- if (ret > 0) {
- char *last_char = core_pattern + strlen(core_pattern) - 1;
-
- if (*last_char == '\n') {
- *last_char = '\0';
- }
- }
- }
-
- if (strlen(core_pattern) == 0) {
+ if (core_pattern_file == -1) {
return -1;
}
+ ssize_t ret = ::read(core_pattern_file, core_pattern, core_pattern_len);
+ ::close(core_pattern_file);
+ if (ret <= 0 || ret >= core_pattern_len || core_pattern[0] == '\n') {
+ return -1;
+ }
+ if (core_pattern[ret-1] == '\n') {
+ core_pattern[ret-1] = '\0';
+ } else {
+ core_pattern[ret] = '\0';
+ }
+
char *pid_pos = strstr(core_pattern, "%p");
int written;
--- a/hotspot/src/os/posix/vm/os_posix.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/posix/vm/os_posix.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -177,6 +177,10 @@
return aligned_base;
}
+int os::log_vsnprintf(char* buf, size_t len, const char* fmt, va_list args) {
+ return vsnprintf(buf, len, fmt, args);
+}
+
void os::Posix::print_load_average(outputStream* st) {
st->print("load average:");
double loadavg[3];
--- a/hotspot/src/os/solaris/vm/jvm_solaris.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/solaris/vm/jvm_solaris.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -73,11 +73,6 @@
if (os::Solaris::is_sig_ignored(sig)) return (void*)1;
}
- /* Check parameterized signals. Don't allow sharing of our interrupt signal */
- if (sig == os::Solaris::SIGinterrupt()) {
- return (void *)-1;
- }
-
void* oldHandler = os::signal(sig, newHandler);
if (oldHandler == os::user_handler()) {
return (void *)2;
--- a/hotspot/src/os/solaris/vm/jvm_solaris.h Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/solaris/vm/jvm_solaris.h Wed Jul 05 21:02:29 2017 +0200
@@ -87,7 +87,6 @@
/* Signal definitions */
#define BREAK_SIGNAL SIGQUIT /* Thread dumping support. */
-#define INTERRUPT_SIGNAL SIGUSR1 /* Interruptible I/O support. */
#define ASYNC_SIGNAL SIGUSR2 /* Watcher & async err support. */
#define SHUTDOWN1_SIGNAL SIGHUP /* Shutdown Hooks support. */
#define SHUTDOWN2_SIGNAL SIGINT
@@ -95,8 +94,7 @@
/* alternative signals used with -XX:+UseAltSigs (or for backward
compatibility with 1.2, -Xusealtsigs) flag. Chosen to be
unlikely to conflict with applications embedding the vm */
-#define ALT_INTERRUPT_SIGNAL (SIGRTMIN + SIGRTMAX)/2 /* alternate intio signal */
-#define ALT_ASYNC_SIGNAL ALT_INTERRUPT_SIGNAL+1 /* alternate async signal */
+#define ALT_ASYNC_SIGNAL (SIGRTMIN + SIGRTMAX)/2 /* alternate async signal */
/* With 1.4.1 libjsig added versioning: used in os_solaris.cpp and jsig.c */
#define JSIG_VERSION_1_4_1 0x30140100
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -138,11 +138,6 @@
#define LGRP_RSRC_MEM 1 /* memory resources */
#endif
-// see thr_setprio(3T) for the basis of these numbers
-#define MinimumPriority 0
-#define NormalPriority 64
-#define MaximumPriority 127
-
// Values for ThreadPriorityPolicy == 1
int prio_policy1[CriticalPriority+1] = {
-99999, 0, 16, 32, 48, 64,
@@ -1003,8 +998,9 @@
// defined for >= Solaris 10. This allows builds on earlier versions
// of Solaris to take advantage of the newly reserved Solaris JVM signals
-// With SIGJVM1, SIGJVM2, INTERRUPT_SIGNAL is SIGJVM1, ASYNC_SIGNAL is SIGJVM2
-// and -XX:+UseAltSigs does nothing since these should have no conflict
+// With SIGJVM1, SIGJVM2, ASYNC_SIGNAL is SIGJVM2 and -XX:+UseAltSigs does
+// nothing since these should have no conflict. Previously INTERRUPT_SIGNAL
+// was SIGJVM1.
//
#if !defined(SIGJVM1)
#define SIGJVM1 39
@@ -1013,7 +1009,7 @@
debug_only(static bool signal_sets_initialized = false);
static sigset_t unblocked_sigs, vm_sigs, allowdebug_blocked_sigs;
-int os::Solaris::_SIGinterrupt = INTERRUPT_SIGNAL;
+
int os::Solaris::_SIGasync = ASYNC_SIGNAL;
bool os::Solaris::is_sig_ignored(int sig) {
@@ -1058,17 +1054,13 @@
sigaddset(&unblocked_sigs, SIGFPE);
if (isJVM1available) {
- os::Solaris::set_SIGinterrupt(SIGJVM1);
os::Solaris::set_SIGasync(SIGJVM2);
} else if (UseAltSigs) {
- os::Solaris::set_SIGinterrupt(ALT_INTERRUPT_SIGNAL);
os::Solaris::set_SIGasync(ALT_ASYNC_SIGNAL);
} else {
- os::Solaris::set_SIGinterrupt(INTERRUPT_SIGNAL);
os::Solaris::set_SIGasync(ASYNC_SIGNAL);
}
- sigaddset(&unblocked_sigs, os::Solaris::SIGinterrupt());
sigaddset(&unblocked_sigs, os::Solaris::SIGasync());
if (!ReduceSignalUsage) {
@@ -1939,8 +1931,6 @@
static int Maxsignum = 0;
static int *ourSigFlags = NULL;
-extern "C" void sigINTRHandler(int, siginfo_t*, void*);
-
int os::Solaris::get_our_sigflags(int sig) {
assert(ourSigFlags!=NULL, "signal data structure not initialized");
assert(sig > 0 && sig < Maxsignum, "vm signal out of expected range");
@@ -2005,8 +1995,7 @@
os::Posix::print_sa_flags(st, sa.sa_flags);
// Check: is it our handler?
- if (handler == CAST_FROM_FN_PTR(address, signalHandler) ||
- handler == CAST_FROM_FN_PTR(address, sigINTRHandler)) {
+ if (handler == CAST_FROM_FN_PTR(address, signalHandler)) {
// It is our signal handler
// check for flags
if (sa.sa_flags != os::Solaris::get_our_sigflags(sig)) {
@@ -2026,13 +2015,11 @@
print_signal_handler(st, SIGPIPE, buf, buflen);
print_signal_handler(st, SIGXFSZ, buf, buflen);
print_signal_handler(st, SIGILL , buf, buflen);
- print_signal_handler(st, INTERRUPT_SIGNAL, buf, buflen);
print_signal_handler(st, ASYNC_SIGNAL, buf, buflen);
print_signal_handler(st, BREAK_SIGNAL, buf, buflen);
print_signal_handler(st, SHUTDOWN1_SIGNAL , buf, buflen);
print_signal_handler(st, SHUTDOWN2_SIGNAL , buf, buflen);
print_signal_handler(st, SHUTDOWN3_SIGNAL, buf, buflen);
- print_signal_handler(st, os::Solaris::SIGinterrupt(), buf, buflen);
print_signal_handler(st, os::Solaris::SIGasync(), buf, buflen);
}
@@ -3146,7 +3133,7 @@
static int myCur = 0;
static bool priocntl_enable = false;
-static const int criticalPrio = 60; // FX/60 is critical thread class/priority on T4
+static const int criticalPrio = FXCriticalPriority;
static int java_MaxPriority_to_os_priority = 0; // Saved mapping
@@ -3796,7 +3783,6 @@
// SIGBUS, SIGSEGV, SIGILL, SIGFPE, BREAK_SIGNAL, SIGPIPE, SIGXFSZ,
// os::Solaris::SIGasync
// It should be consulted by handlers for any of those signals.
-// It explicitly does not recognize os::Solaris::SIGinterrupt
//
// The caller of this routine must pass in the three arguments supplied
// to the function referred to in the "sa_sigaction" (not the "sa_handler")
@@ -3818,20 +3804,6 @@
errno = orig_errno;
}
-// Do not delete - if guarantee is ever removed, a signal handler (even empty)
-// is needed to provoke threads blocked on IO to return an EINTR
-// Note: this explicitly does NOT call JVM_handle_solaris_signal and
-// does NOT participate in signal chaining due to requirement for
-// NOT setting SA_RESTART to make EINTR work.
-extern "C" void sigINTRHandler(int sig, siginfo_t* info, void* ucVoid) {
- if (UseSignalChaining) {
- struct sigaction *actp = os::Solaris::get_chained_signal_action(sig);
- if (actp && actp->sa_handler) {
- vm_exit_during_initialization("Signal chaining detected for VM interrupt signal, try -XX:+UseAltSigs");
- }
- }
-}
-
// This boolean allows users to forward their own non-matching signals
// to JVM_handle_solaris_signal, harmlessly.
bool os::Solaris::signal_handlers_are_installed = false;
@@ -3969,13 +3941,6 @@
// not using stack banging
if (!UseStackBanging && sig == SIGSEGV) {
sigAct.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK;
- } else if (sig == os::Solaris::SIGinterrupt()) {
- // Interruptible i/o requires SA_RESTART cleared so EINTR
- // is returned instead of restarting system calls
- sigemptyset(&sigAct.sa_mask);
- sigAct.sa_handler = NULL;
- sigAct.sa_flags = SA_SIGINFO;
- sigAct.sa_sigaction = sigINTRHandler;
} else {
sigAct.sa_flags = SA_SIGINFO | SA_RESTART;
}
@@ -4027,7 +3992,6 @@
}
// See comments above for using JVM1/JVM2 and UseAltSigs
- DO_SIGNAL_CHECK(os::Solaris::SIGinterrupt());
DO_SIGNAL_CHECK(os::Solaris::SIGasync());
}
@@ -4072,12 +4036,9 @@
break;
default:
- int intrsig = os::Solaris::SIGinterrupt();
int asynsig = os::Solaris::SIGasync();
- if (sig == intrsig) {
- jvmHandler = CAST_FROM_FN_PTR(address, sigINTRHandler);
- } else if (sig == asynsig) {
+ if (sig == asynsig) {
jvmHandler = CAST_FROM_FN_PTR(address, signalHandler);
} else {
return;
@@ -4148,8 +4109,7 @@
set_signal_handler(SIGFPE, true, true);
- if (os::Solaris::SIGinterrupt() > OLDMAXSIGNUM || os::Solaris::SIGasync() > OLDMAXSIGNUM) {
-
+ if (os::Solaris::SIGasync() > OLDMAXSIGNUM) {
// Pre-1.4.1 Libjsig limited to signal chaining signals <= 32 so
// can not register overridable signals which might be > 32
if (libjsig_is_loaded && libjsigversion <= JSIG_VERSION_1_4_1) {
@@ -4159,8 +4119,6 @@
}
}
- // Never ok to chain our SIGinterrupt
- set_signal_handler(os::Solaris::SIGinterrupt(), true, false);
set_signal_handler(os::Solaris::SIGasync(), true, true);
if (libjsig_is_loaded && !libjsigdone) {
--- a/hotspot/src/os/solaris/vm/os_solaris.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/solaris/vm/os_solaris.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,14 @@
// Solaris_OS defines the interface to Solaris operating systems
+// see thr_setprio(3T) for the basis of these numbers
+#define MinimumPriority 0
+#define NormalPriority 64
+#define MaximumPriority 127
+
+// FX/60 is critical thread class/priority on T4
+#define FXCriticalPriority 60
+
// Information about the protection of the page at address '0' on this os.
static bool zero_page_read_protected() { return true; }
@@ -114,16 +122,13 @@
static void save_preinstalled_handler(int, struct sigaction&);
static void check_signal_handler(int sig);
// For overridable signals
- static int _SIGinterrupt; // user-overridable INTERRUPT_SIGNAL
static int _SIGasync; // user-overridable ASYNC_SIGNAL
- static void set_SIGinterrupt(int newsig) { _SIGinterrupt = newsig; }
static void set_SIGasync(int newsig) { _SIGasync = newsig; }
public:
// Large Page Support--ISM.
static bool largepage_range(char* addr, size_t size);
- static int SIGinterrupt() { return _SIGinterrupt; }
static int SIGasync() { return _SIGasync; }
static address handler_start, handler_end; // start and end pc of thr_sighndlrinfo
--- a/hotspot/src/os/windows/vm/attachListener_windows.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/windows/vm/attachListener_windows.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -191,7 +191,8 @@
// check that all paramteres to the operation
if (strlen(cmd) > AttachOperation::name_length_max) return ATTACH_ERROR_ILLEGALARG;
if (strlen(arg0) > AttachOperation::arg_length_max) return ATTACH_ERROR_ILLEGALARG;
- if (strlen(arg0) > AttachOperation::arg_length_max) return ATTACH_ERROR_ILLEGALARG;
+ if (strlen(arg1) > AttachOperation::arg_length_max) return ATTACH_ERROR_ILLEGALARG;
+ if (strlen(arg2) > AttachOperation::arg_length_max) return ATTACH_ERROR_ILLEGALARG;
if (strlen(pipename) > Win32AttachOperation::pipe_name_max) return ATTACH_ERROR_ILLEGALARG;
// check for a well-formed pipename
--- a/hotspot/src/os/windows/vm/os_windows.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os/windows/vm/os_windows.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -1608,6 +1608,15 @@
if (nl != NULL) *nl = '\0';
}
+int os::log_vsnprintf(char* buf, size_t len, const char* fmt, va_list args) {
+ int ret = vsnprintf(buf, len, fmt, args);
+ // Get the correct buffer size if buf is too small
+ if (ret < 0) {
+ return _vscprintf(fmt, args);
+ }
+ return ret;
+}
+
void os::print_os_info_brief(outputStream* st) {
os::print_os_info(st);
}
--- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -325,8 +325,6 @@
}
}
- guarantee(sig != os::Solaris::SIGinterrupt(), "Can not chain VM interrupt signal, try -XX:+UseAltSigs");
-
if (sig == os::Solaris::SIGasync()) {
if (thread || vmthread) {
OSThread::SR_handler(t, uc);
--- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -382,8 +382,6 @@
}
}
- guarantee(sig != os::Solaris::SIGinterrupt(), "Can not chain VM interrupt signal, try -XX:+UseAltSigs");
-
if (sig == os::Solaris::SIGasync()) {
if(thread || vmthread){
OSThread::SR_handler(t, uc);
--- a/hotspot/src/share/vm/asm/codeBuffer.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/asm/codeBuffer.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -873,6 +873,7 @@
// Figure new capacity for each section.
csize_t new_capacity[SECT_LIMIT];
+ memset(new_capacity, 0, sizeof(csize_t) * SECT_LIMIT);
csize_t new_total_cap
= figure_expanded_capacities(which_cs, amount, new_capacity);
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -92,6 +92,7 @@
// Used for backward compatibility reasons:
// - to check NameAndType_info signatures more aggressively
+// - to disallow argument and require ACC_STATIC for <clinit> methods
#define JAVA_7_VERSION 51
// Extension method support.
@@ -1997,9 +1998,7 @@
} else if ((flags & JVM_ACC_STATIC) == JVM_ACC_STATIC) {
flags &= JVM_ACC_STATIC | JVM_ACC_STRICT;
} else {
- // As of major_version 51, a method named <clinit> without ACC_STATIC is
- // just another method. So, do a normal method modifer check.
- verify_legal_method_modifiers(flags, is_interface, name, CHECK_(nullHandle));
+ classfile_parse_error("Method <clinit> is not static in class file %s", CHECK_(nullHandle));
}
} else {
verify_legal_method_modifiers(flags, is_interface, name, CHECK_(nullHandle));
@@ -5159,6 +5158,14 @@
return -2;
}
+ // Class initializers cannot have args for class format version >= 51.
+ if (name == vmSymbols::class_initializer_name() &&
+ signature != vmSymbols::void_method_signature() &&
+ _major_version >= JAVA_7_VERSION) {
+ throwIllegalSignature("Method", name, signature, CHECK_0);
+ return 0;
+ }
+
unsigned int args_size = 0;
char buf[fixed_buffer_size];
char* p = signature->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size);
@@ -5182,8 +5189,8 @@
// The first non-signature thing better be a ')'
if ((length > 0) && (*p++ == JVM_SIGNATURE_ENDFUNC)) {
length--;
- if (name == vmSymbols::object_initializer_name()) {
- // All "<init>" methods must return void
+ if (name->utf8_length() > 0 && name->byte_at(0) == '<') {
+ // All internal methods must return void
if ((length == 1) && (p[0] == JVM_SIGNATURE_VOID)) {
return args_size;
}
--- a/hotspot/src/share/vm/classfile/defaultMethods.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/classfile/defaultMethods.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -26,6 +26,7 @@
#include "classfile/bytecodeAssembler.hpp"
#include "classfile/defaultMethods.hpp"
#include "classfile/symbolTable.hpp"
+#include "logging/log.hpp"
#include "memory/allocation.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/resourceArea.hpp"
@@ -74,7 +75,6 @@
}
};
-#ifndef PRODUCT
static void print_slot(outputStream* str, Symbol* name, Symbol* signature) {
ResourceMark rm;
str->print("%s%s", name->as_C_string(), signature->as_C_string());
@@ -87,7 +87,6 @@
}
print_slot(str, mo->name(), mo->signature());
}
-#endif // ndef PRODUCT
/**
* Perform a depth-first iteration over the class hierarchy, applying
@@ -246,21 +245,22 @@
}
};
-#ifndef PRODUCT
class PrintHierarchy : public HierarchyVisitor<PrintHierarchy> {
+ private:
+ outputStream* _st;
public:
-
bool visit() {
InstanceKlass* cls = current_class();
- streamIndentor si(tty, current_depth() * 2);
- tty->indent().print_cr("%s", cls->name()->as_C_string());
+ streamIndentor si(_st, current_depth() * 2);
+ _st->indent().print_cr("%s", cls->name()->as_C_string());
return true;
}
void* new_node_data(InstanceKlass* cls) { return NULL; }
void free_node_data(void* data) { return; }
+
+ PrintHierarchy(outputStream* st = tty) : _st(st) {}
};
-#endif // ndef PRODUCT
// Used to register InstanceKlass objects and all related metadata structures
// (Methods, ConstantPools) as "in-use" by the current thread so that they can't
@@ -434,9 +434,11 @@
} else if (num_defaults > 1) {
_exception_message = generate_conflicts_message(&qualified_methods,CHECK);
_exception_name = vmSymbols::java_lang_IncompatibleClassChangeError();
- if (TraceDefaultMethods) {
- _exception_message->print_value_on(tty);
- tty->cr();
+ if (log_is_enabled(Debug, defaultmethods)) {
+ ResourceMark rm;
+ outputStream* logstream = LogHandle(defaultmethods)::debug_stream();
+ _exception_message->print_value_on(logstream);
+ logstream->cr();
}
}
}
@@ -450,27 +452,6 @@
return false;
}
-#ifndef PRODUCT
- void print_sig_on(outputStream* str, Symbol* signature, int indent) const {
- streamIndentor si(str, indent * 2);
-
- str->indent().print_cr("Logical Method %s:", signature->as_C_string());
-
- streamIndentor si2(str);
- for (int i = 0; i < _members.length(); ++i) {
- str->indent();
- print_method(str, _members.at(i).first);
- if (_members.at(i).second == DISQUALIFIED) {
- str->print(" (disqualified)");
- }
- str->cr();
- }
-
- if (_selected_target != NULL) {
- print_selected(str, 1);
- }
- }
-
void print_selected(outputStream* str, int indent) const {
assert(has_target(), "Should be called otherwise");
streamIndentor si(str, indent * 2);
@@ -478,7 +459,7 @@
print_method(str, _selected_target);
Klass* method_holder = _selected_target->method_holder();
if (!method_holder->is_interface()) {
- tty->print(" : in superclass");
+ str->print(" : in superclass");
}
str->cr();
}
@@ -489,7 +470,6 @@
streamIndentor si(str, indent * 2);
str->indent().print_cr("%s: %s", _exception_name->as_C_string(), _exception_message->as_C_string());
}
-#endif // ndef PRODUCT
};
Symbol* MethodFamily::generate_no_defaults_message(TRAPS) const {
@@ -608,11 +588,9 @@
bool is_bound() { return _binding != NULL; }
MethodFamily* get_binding() { return _binding; }
-#ifndef PRODUCT
void print_on(outputStream* str) const {
print_slot(str, name(), signature());
}
-#endif // ndef PRODUCT
};
static bool already_in_vtable_slots(GrowableArray<EmptyVtableSlot*>* slots, Method* m) {
@@ -681,17 +659,18 @@
super = super->java_super();
}
-#ifndef PRODUCT
- if (TraceDefaultMethods) {
- tty->print_cr("Slots that need filling:");
- streamIndentor si(tty);
+ if (log_is_enabled(Debug, defaultmethods)) {
+ log_debug(defaultmethods)("Slots that need filling:");
+ ResourceMark rm;
+ outputStream* logstream = LogHandle(defaultmethods)::debug_stream();
+ streamIndentor si(logstream);
for (int i = 0; i < slots->length(); ++i) {
- tty->indent();
- slots->at(i)->print_on(tty);
- tty->cr();
+ logstream->indent();
+ slots->at(i)->print_on(logstream);
+ logstream->cr();
}
}
-#endif // ndef PRODUCT
+
return slots;
}
@@ -812,46 +791,32 @@
KeepAliveVisitor loadKeepAlive(&keepAlive);
loadKeepAlive.run(klass);
-#ifndef PRODUCT
- if (TraceDefaultMethods) {
- ResourceMark rm; // be careful with these!
- tty->print_cr("%s %s requires default method processing",
- klass->is_interface() ? "Interface" : "Class",
- klass->name()->as_klass_external_name());
- PrintHierarchy printer;
+ if (log_is_enabled(Debug, defaultmethods)) {
+ ResourceMark rm;
+ log_debug(defaultmethods)("%s %s requires default method processing",
+ klass->is_interface() ? "Interface" : "Class",
+ klass->name()->as_klass_external_name());
+ PrintHierarchy printer(LogHandle(defaultmethods)::debug_stream());
printer.run(klass);
}
-#endif // ndef PRODUCT
GrowableArray<EmptyVtableSlot*>* empty_slots =
find_empty_vtable_slots(klass, mirandas, CHECK);
for (int i = 0; i < empty_slots->length(); ++i) {
EmptyVtableSlot* slot = empty_slots->at(i);
-#ifndef PRODUCT
- if (TraceDefaultMethods) {
- streamIndentor si(tty, 2);
- tty->indent().print("Looking for default methods for slot ");
- slot->print_on(tty);
- tty->cr();
+ if (log_is_enabled(Debug, defaultmethods)) {
+ outputStream* logstream = LogHandle(defaultmethods)::debug_stream();
+ streamIndentor si(logstream, 2);
+ logstream->indent().print("Looking for default methods for slot ");
+ slot->print_on(logstream);
+ logstream->cr();
}
-#endif // ndef PRODUCT
-
generate_erased_defaults(klass, empty_slots, slot, CHECK);
- }
-#ifndef PRODUCT
- if (TraceDefaultMethods) {
- tty->print_cr("Creating defaults and overpasses...");
}
-#endif // ndef PRODUCT
-
+ log_debug(defaultmethods)("Creating defaults and overpasses...");
create_defaults_and_exceptions(empty_slots, klass, CHECK);
-
-#ifndef PRODUCT
- if (TraceDefaultMethods) {
- tty->print_cr("Default method processing complete");
- }
-#endif // ndef PRODUCT
+ log_debug(defaultmethods)("Default method processing complete");
}
static int assemble_method_error(
@@ -947,18 +912,18 @@
MethodFamily* method = slot->get_binding();
BytecodeBuffer buffer;
-#ifndef PRODUCT
- if (TraceDefaultMethods) {
- tty->print("for slot: ");
- slot->print_on(tty);
- tty->cr();
+ if (log_is_enabled(Debug, defaultmethods)) {
+ ResourceMark rm;
+ outputStream* logstream = LogHandle(defaultmethods)::debug_stream();
+ logstream->print("for slot: ");
+ slot->print_on(logstream);
+ logstream->cr();
if (method->has_target()) {
- method->print_selected(tty, 1);
+ method->print_selected(logstream, 1);
} else if (method->throws_exception()) {
- method->print_exception(tty, 1);
+ method->print_exception(logstream, 1);
}
}
-#endif // ndef PRODUCT
if (method->has_target()) {
Method* selected = method->get_selected_target();
@@ -982,12 +947,9 @@
}
}
-#ifndef PRODUCT
- if (TraceDefaultMethods) {
- tty->print_cr("Created %d overpass methods", overpasses.length());
- tty->print_cr("Created %d default methods", defaults.length());
- }
-#endif // ndef PRODUCT
+
+ log_debug(defaultmethods)("Created %d overpass methods", overpasses.length());
+ log_debug(defaultmethods)("Created %d default methods", defaults.length());
if (overpasses.length() > 0) {
switchover_constant_pool(&bpool, klass, &overpasses, CHECK);
--- a/hotspot/src/share/vm/classfile/verifier.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/classfile/verifier.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -2846,7 +2846,7 @@
if (sig_stream.type() != T_VOID) {
if (method_name == vmSymbols::object_initializer_name()) {
// <init> method must have a void return type
- /* Unreachable? Class file parser verifies that <init> methods have
+ /* Unreachable? Class file parser verifies that methods with '<' have
* void return */
verify_error(ErrorContext::bad_code(bci),
"Return type must be void in <init> method");
--- a/hotspot/src/share/vm/code/nmethod.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/code/nmethod.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -674,10 +674,6 @@
return nm;
}
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable:4355) // warning C4355: 'this' : used in base member initializer list
-#endif
// For native wrappers
nmethod::nmethod(
Method* method,
@@ -767,10 +763,6 @@
}
}
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
void* nmethod::operator new(size_t size, int nmethod_size, int comp_level) throw () {
return CodeCache::allocate(nmethod_size, CodeCache::get_code_blob_type(comp_level));
}
@@ -2303,7 +2295,7 @@
assert(cur != NULL, "not NULL-terminated");
nmethod* next = cur->_oops_do_mark_link;
cur->_oops_do_mark_link = NULL;
- cur->verify_oop_relocations();
+ DEBUG_ONLY(cur->verify_oop_relocations());
NOT_PRODUCT(if (TraceScavenge) cur->print_on(tty, "oops_do, unmark"));
cur = next;
}
--- a/hotspot/src/share/vm/code/relocInfo.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/code/relocInfo.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -438,10 +438,10 @@
void Relocation::const_verify_data_value(address x) {
#ifdef _LP64
if (format() == relocInfo::narrow_oop_in_const) {
- assert(*(narrowOop*)addr() == oopDesc::encode_heap_oop((oop) x), "must agree");
+ guarantee(*(narrowOop*)addr() == oopDesc::encode_heap_oop((oop) x), "must agree");
} else {
#endif
- assert(*(address*)addr() == x, "must agree");
+ guarantee(*(address*)addr() == x, "must agree");
#ifdef _LP64
}
#endif
--- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -1542,9 +1542,7 @@
do_compaction_work(clear_all_soft_refs);
// Has the GC time limit been exceeded?
- size_t max_eden_size = _young_gen->max_capacity() -
- _young_gen->to()->capacity() -
- _young_gen->from()->capacity();
+ size_t max_eden_size = _young_gen->max_eden_size();
GCCause::Cause gc_cause = gch->gc_cause();
size_policy()->check_gc_overhead_limit(_young_gen->used(),
_young_gen->eden()->used(),
@@ -7350,6 +7348,14 @@
set_freeFinger(freeFinger);
set_freeRangeInFreeLists(freeRangeInFreeLists);
+ if (CMSTestInFreeList) {
+ if (freeRangeInFreeLists) {
+ FreeChunk* fc = (FreeChunk*) freeFinger;
+ assert(fc->is_free(), "A chunk on the free list should be free.");
+ assert(fc->size() > 0, "Free range should have a size");
+ assert(_sp->verify_chunk_in_free_list(fc), "Chunk is not in free lists");
+ }
+ }
}
// Note that the sweeper runs concurrently with mutators. Thus,
@@ -7502,7 +7508,12 @@
void SweepClosure::do_already_free_chunk(FreeChunk* fc) {
const size_t size = fc->size();
-
+ // Chunks that cannot be coalesced are not in the
+ // free lists.
+ if (CMSTestInFreeList && !fc->cantCoalesce()) {
+ assert(_sp->verify_chunk_in_free_list(fc),
+ "free chunk should be in free lists");
+ }
// a chunk that is already free, should not have been
// marked in the bit map
HeapWord* const addr = (HeapWord*) fc;
@@ -7609,6 +7620,9 @@
// of the adaptive free list allocator.
const bool fcInFreeLists = fc->is_free();
assert((HeapWord*)fc <= _limit, "sweep invariant");
+ if (CMSTestInFreeList && fcInFreeLists) {
+ assert(_sp->verify_chunk_in_free_list(fc), "free chunk is not in free lists");
+ }
if (CMSTraceSweeper) {
gclog_or_tty->print_cr(" -- pick up another chunk at " PTR_FORMAT " (" SIZE_FORMAT ")", p2i(fc), chunkSize);
@@ -7660,7 +7674,11 @@
if (freeRangeInFreeLists()) {
FreeChunk* const ffc = (FreeChunk*)freeFinger();
assert(ffc->size() == pointer_delta(fc_addr, freeFinger()),
- "Size of free range is inconsistent with chunk size.");
+ "Size of free range is inconsistent with chunk size.");
+ if (CMSTestInFreeList) {
+ assert(_sp->verify_chunk_in_free_list(ffc),
+ "Chunk is not in free lists");
+ }
_sp->coalDeath(ffc->size());
_sp->removeFreeChunkFromFreeLists(ffc);
set_freeRangeInFreeLists(false);
@@ -7729,6 +7747,12 @@
assert(size > 0,
"A zero sized chunk cannot be added to the free lists.");
if (!freeRangeInFreeLists()) {
+ if (CMSTestInFreeList) {
+ FreeChunk* fc = (FreeChunk*) chunk;
+ fc->set_size(size);
+ assert(!_sp->verify_chunk_in_free_list(fc),
+ "chunk should not be in free lists yet");
+ }
if (CMSTraceSweeper) {
gclog_or_tty->print_cr(" -- add free block " PTR_FORMAT " (" SIZE_FORMAT ") to free lists",
p2i(chunk), size);
--- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -57,10 +57,6 @@
#include "utilities/globalDefinitions.hpp"
#include "utilities/stack.inline.hpp"
-#ifdef _MSC_VER
-#pragma warning( push )
-#pragma warning( disable:4355 ) // 'this' : used in base member initializer list
-#endif
ParScanThreadState::ParScanThreadState(Space* to_space_,
ParNewGeneration* young_gen_,
Generation* old_gen_,
@@ -104,9 +100,6 @@
_old_gen_closure.set_generation(old_gen_);
_old_gen_root_closure.set_generation(old_gen_);
}
-#ifdef _MSC_VER
-#pragma warning( pop )
-#endif
void ParScanThreadState::record_survivor_plab(HeapWord* plab_start,
size_t plab_word_size) {
@@ -597,10 +590,6 @@
par_scan_state.evacuate_followers_closure().do_void();
}
-#ifdef _MSC_VER
-#pragma warning( push )
-#pragma warning( disable:4355 ) // 'this' : used in base member initializer list
-#endif
ParNewGeneration::ParNewGeneration(ReservedSpace rs, size_t initial_byte_size)
: DefNewGeneration(rs, initial_byte_size, "PCopy"),
_overflow_list(NULL),
@@ -643,9 +632,6 @@
ParallelGCThreads, CHECK);
}
}
-#ifdef _MSC_VER
-#pragma warning( pop )
-#endif
// ParNewGeneration::
ParKeepAliveClosure::ParKeepAliveClosure(ParScanWeakRefClosure* cl) :
--- a/hotspot/src/share/vm/gc/g1/concurrentMark.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/concurrentMark.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -454,10 +454,6 @@
return true;
}
-#ifdef _MSC_VER // the use of 'this' below gets a warning, make it go away
-#pragma warning( disable:4355 ) // 'this' : used in base member initializer list
-#endif // _MSC_VER
-
uint ConcurrentMark::scale_parallel_threads(uint n_par_threads) {
return MAX2((n_par_threads + 2) / 4, 1U);
}
@@ -509,19 +505,6 @@
_count_card_bitmaps(NULL),
_count_marked_bytes(NULL),
_completed_initialization(false) {
- CMVerboseLevel verbose_level = (CMVerboseLevel) G1MarkingVerboseLevel;
- if (verbose_level < no_verbose) {
- verbose_level = no_verbose;
- }
- if (verbose_level > high_verbose) {
- verbose_level = high_verbose;
- }
- _verbose_level = verbose_level;
-
- if (verbose_low()) {
- gclog_or_tty->print_cr("[global] init, heap start = " PTR_FORMAT ", "
- "heap end = " PTR_FORMAT, p2i(_heap_start), p2i(_heap_end));
- }
_markBitMap1.initialize(g1h->reserved_region(), prev_bitmap_storage);
_markBitMap2.initialize(g1h->reserved_region(), next_bitmap_storage);
@@ -706,10 +689,6 @@
// Reset all the marking data structures and any necessary flags
reset_marking_state();
- if (verbose_low()) {
- gclog_or_tty->print_cr("[global] resetting");
- }
-
// We do reset all of them, since different phases will use
// different number of active threads. So, it's easiest to have all
// of them ready.
@@ -823,12 +802,8 @@
// This closure can be called concurrently to the mutator, so we must make sure
// that the result of the getNextMarkedWordAddress() call is compared to the
// value passed to it as limit to detect any found bits.
- // We can use the region's orig_end() for the limit and the comparison value
- // as it always contains the "real" end of the region that never changes and
- // has no side effects.
- // Due to the latter, there can also be no problem with the compiler generating
- // reloads of the orig_end() call.
- HeapWord* end = r->orig_end();
+ // end never changes in G1.
+ HeapWord* end = r->end();
return _bitmap->getNextMarkedWordAddress(r->bottom(), end) != end;
}
};
@@ -842,9 +817,7 @@
class NoteStartOfMarkHRClosure: public HeapRegionClosure {
public:
bool doHeapRegion(HeapRegion* r) {
- if (!r->is_continues_humongous()) {
- r->note_start_of_marking();
- }
+ r->note_start_of_marking();
return false;
}
};
@@ -918,11 +891,6 @@
void ConcurrentMark::enter_first_sync_barrier(uint worker_id) {
bool barrier_aborted;
-
- if (verbose_low()) {
- gclog_or_tty->print_cr("[%u] entering first barrier", worker_id);
- }
-
{
SuspendibleThreadSetLeaver sts_leave(concurrent());
barrier_aborted = !_first_overflow_barrier_sync.enter();
@@ -931,14 +899,6 @@
// at this point everyone should have synced up and not be doing any
// more work
- if (verbose_low()) {
- if (barrier_aborted) {
- gclog_or_tty->print_cr("[%u] aborted first barrier", worker_id);
- } else {
- gclog_or_tty->print_cr("[%u] leaving first barrier", worker_id);
- }
- }
-
if (barrier_aborted) {
// If the barrier aborted we ignore the overflow condition and
// just abort the whole marking phase as quickly as possible.
@@ -974,26 +934,10 @@
}
void ConcurrentMark::enter_second_sync_barrier(uint worker_id) {
- bool barrier_aborted;
-
- if (verbose_low()) {
- gclog_or_tty->print_cr("[%u] entering second barrier", worker_id);
- }
-
- {
- SuspendibleThreadSetLeaver sts_leave(concurrent());
- barrier_aborted = !_second_overflow_barrier_sync.enter();
- }
+ SuspendibleThreadSetLeaver sts_leave(concurrent());
+ _second_overflow_barrier_sync.enter();
// at this point everything should be re-initialized and ready to go
-
- if (verbose_low()) {
- if (barrier_aborted) {
- gclog_or_tty->print_cr("[%u] aborted second barrier", worker_id);
- } else {
- gclog_or_tty->print_cr("[%u] leaving second barrier", worker_id);
- }
- }
}
#ifndef PRODUCT
@@ -1332,22 +1276,10 @@
// Takes a region that's not empty (i.e., it has at least one
// live object in it and sets its corresponding bit on the region
- // bitmap to 1. If the region is "starts humongous" it will also set
- // to 1 the bits on the region bitmap that correspond to its
- // associated "continues humongous" regions.
+ // bitmap to 1.
void set_bit_for_region(HeapRegion* hr) {
- assert(!hr->is_continues_humongous(), "should have filtered those out");
-
BitMap::idx_t index = (BitMap::idx_t) hr->hrm_index();
- if (!hr->is_starts_humongous()) {
- // Normal (non-humongous) case: just set the bit.
- _region_bm->par_at_put(index, true);
- } else {
- // Starts humongous case: calculate how many regions are part of
- // this humongous region and then set the bit range.
- BitMap::idx_t end_index = (BitMap::idx_t) hr->last_hc_index();
- _region_bm->par_at_put_range(index, end_index, true);
- }
+ _region_bm->par_at_put(index, true);
}
public:
@@ -1371,18 +1303,6 @@
_bm(bm), _region_marked_bytes(0) { }
bool doHeapRegion(HeapRegion* hr) {
-
- if (hr->is_continues_humongous()) {
- // We will ignore these here and process them when their
- // associated "starts humongous" region is processed (see
- // set_bit_for_heap_region()). Note that we cannot rely on their
- // associated "starts humongous" region to have their bit set to
- // 1 since, due to the region chunking in the parallel region
- // iteration, a "continues humongous" region might be visited
- // before its associated "starts humongous".
- return false;
- }
-
HeapWord* ntams = hr->next_top_at_mark_start();
HeapWord* start = hr->bottom();
@@ -1420,6 +1340,11 @@
// Add the size of this object to the number of marked bytes.
marked_bytes += (size_t)obj_sz * HeapWordSize;
+ // This will happen if we are handling a humongous object that spans
+ // several heap regions.
+ if (obj_end > hr->end()) {
+ break;
+ }
// Find the next marked object after this one.
start = _bm->getNextMarkedWordAddress(obj_end, ntams);
}
@@ -1471,7 +1396,6 @@
CalcLiveObjectsClosure _calc_cl;
BitMap* _region_bm; // Region BM to be verified
BitMap* _card_bm; // Card BM to be verified
- bool _verbose; // verbose output?
BitMap* _exp_region_bm; // Expected Region BM values
BitMap* _exp_card_bm; // Expected card BM values
@@ -1483,28 +1407,16 @@
BitMap* region_bm,
BitMap* card_bm,
BitMap* exp_region_bm,
- BitMap* exp_card_bm,
- bool verbose) :
+ BitMap* exp_card_bm) :
_g1h(g1h), _cm(g1h->concurrent_mark()),
_calc_cl(_cm->nextMarkBitMap(), g1h, exp_region_bm, exp_card_bm),
- _region_bm(region_bm), _card_bm(card_bm), _verbose(verbose),
+ _region_bm(region_bm), _card_bm(card_bm),
_exp_region_bm(exp_region_bm), _exp_card_bm(exp_card_bm),
_failures(0) { }
int failures() const { return _failures; }
bool doHeapRegion(HeapRegion* hr) {
- if (hr->is_continues_humongous()) {
- // We will ignore these here and process them when their
- // associated "starts humongous" region is processed (see
- // set_bit_for_heap_region()). Note that we cannot rely on their
- // associated "starts humongous" region to have their bit set to
- // 1 since, due to the region chunking in the parallel region
- // iteration, a "continues humongous" region might be visited
- // before its associated "starts humongous".
- return false;
- }
-
int failures = 0;
// Call the CalcLiveObjectsClosure to walk the marking bitmap for
@@ -1513,22 +1425,29 @@
bool res = _calc_cl.doHeapRegion(hr);
assert(res == false, "should be continuing");
- MutexLockerEx x((_verbose ? ParGCRareEvent_lock : NULL),
- Mutex::_no_safepoint_check_flag);
-
// Verify the marked bytes for this region.
size_t exp_marked_bytes = _calc_cl.region_marked_bytes();
size_t act_marked_bytes = hr->next_marked_bytes();
- // We're not OK if expected marked bytes > actual marked bytes. It means
- // we have missed accounting some objects during the actual marking.
if (exp_marked_bytes > act_marked_bytes) {
- if (_verbose) {
- gclog_or_tty->print_cr("Region %u: marked bytes mismatch: "
- "expected: " SIZE_FORMAT ", actual: " SIZE_FORMAT,
- hr->hrm_index(), exp_marked_bytes, act_marked_bytes);
+ if (hr->is_starts_humongous()) {
+ // For start_humongous regions, the size of the whole object will be
+ // in exp_marked_bytes.
+ HeapRegion* region = hr;
+ int num_regions;
+ for (num_regions = 0; region != NULL; num_regions++) {
+ region = _g1h->next_region_in_humongous(region);
+ }
+ if ((num_regions-1) * HeapRegion::GrainBytes >= exp_marked_bytes) {
+ failures += 1;
+ } else if (num_regions * HeapRegion::GrainBytes < exp_marked_bytes) {
+ failures += 1;
+ }
+ } else {
+ // We're not OK if expected marked bytes > actual marked bytes. It means
+ // we have missed accounting some objects during the actual marking.
+ failures += 1;
}
- failures += 1;
}
// Verify the bit, for this region, in the actual and expected
@@ -1540,12 +1459,6 @@
bool expected = _exp_region_bm->at(index);
bool actual = _region_bm->at(index);
if (expected && !actual) {
- if (_verbose) {
- gclog_or_tty->print_cr("Region %u: region bitmap mismatch: "
- "expected: %s, actual: %s",
- hr->hrm_index(),
- BOOL_TO_STR(expected), BOOL_TO_STR(actual));
- }
failures += 1;
}
@@ -1561,23 +1474,10 @@
actual = _card_bm->at(i);
if (expected && !actual) {
- if (_verbose) {
- gclog_or_tty->print_cr("Region %u: card bitmap mismatch at " SIZE_FORMAT ": "
- "expected: %s, actual: %s",
- hr->hrm_index(), i,
- BOOL_TO_STR(expected), BOOL_TO_STR(actual));
- }
failures += 1;
}
}
- if (failures > 0 && _verbose) {
- gclog_or_tty->print_cr("Region " HR_FORMAT ", ntams: " PTR_FORMAT ", "
- "marked_bytes: calc/actual " SIZE_FORMAT "/" SIZE_FORMAT,
- HR_FORMAT_PARAMS(hr), p2i(hr->next_top_at_mark_start()),
- _calc_cl.region_marked_bytes(), hr->next_marked_bytes());
- }
-
_failures += failures;
// We could stop iteration over the heap when we
@@ -1599,7 +1499,6 @@
BitMap* _expected_card_bm;
int _failures;
- bool _verbose;
HeapRegionClaimer _hrclaimer;
@@ -1611,13 +1510,11 @@
_g1h(g1h), _cm(_g1h->concurrent_mark()),
_actual_region_bm(region_bm), _actual_card_bm(card_bm),
_expected_region_bm(expected_region_bm), _expected_card_bm(expected_card_bm),
- _failures(0), _verbose(false),
+ _failures(0),
_n_workers(_g1h->workers()->active_workers()), _hrclaimer(_n_workers) {
assert(VerifyDuringGC, "don't call this otherwise");
assert(_expected_card_bm->size() == _actual_card_bm->size(), "sanity");
assert(_expected_region_bm->size() == _actual_region_bm->size(), "sanity");
-
- _verbose = _cm->verbose_medium();
}
void work(uint worker_id) {
@@ -1626,8 +1523,7 @@
VerifyLiveObjectDataHRClosure verify_cl(_g1h,
_actual_region_bm, _actual_card_bm,
_expected_region_bm,
- _expected_card_bm,
- _verbose);
+ _expected_card_bm);
_g1h->heap_region_par_iterate(&verify_cl, worker_id, &_hrclaimer);
@@ -1652,18 +1548,6 @@
CMCountDataClosureBase(g1h, region_bm, card_bm) { }
bool doHeapRegion(HeapRegion* hr) {
-
- if (hr->is_continues_humongous()) {
- // We will ignore these here and process them when their
- // associated "starts humongous" region is processed (see
- // set_bit_for_heap_region()). Note that we cannot rely on their
- // associated "starts humongous" region to have their bit set to
- // 1 since, due to the region chunking in the parallel region
- // iteration, a "continues humongous" region might be visited
- // before its associated "starts humongous".
- return false;
- }
-
HeapWord* ntams = hr->next_top_at_mark_start();
HeapWord* top = hr->top();
@@ -1760,7 +1644,7 @@
const HeapRegionSetCount& humongous_regions_removed() { return _humongous_regions_removed; }
bool doHeapRegion(HeapRegion *hr) {
- if (hr->is_continues_humongous() || hr->is_archive()) {
+ if (hr->is_archive()) {
return false;
}
// We use a claim value of zero here because all regions
@@ -1772,7 +1656,6 @@
_freed_bytes += hr->used();
hr->set_containing_set(NULL);
if (hr->is_humongous()) {
- assert(hr->is_starts_humongous(), "we should only see starts humongous");
_humongous_regions_removed.increment(1u, hr->capacity());
_g1->free_humongous_region(hr, _local_cleanup_list, true);
} else {
@@ -2095,12 +1978,6 @@
template <class T> void do_oop_work(T* p) {
if (!_cm->has_overflown()) {
oop obj = oopDesc::load_decode_heap_oop(p);
- if (_cm->verbose_high()) {
- gclog_or_tty->print_cr("\t[%u] we're looking at location "
- "*" PTR_FORMAT " = " PTR_FORMAT,
- _task->worker_id(), p2i(p), p2i((void*) obj));
- }
-
_task->deal_with_reference(obj);
_ref_counter--;
@@ -2129,10 +2006,6 @@
} while (_task->has_aborted() && !_cm->has_overflown());
_ref_counter = _ref_counter_limit;
}
- } else {
- if (_cm->verbose_high()) {
- gclog_or_tty->print_cr("\t[%u] CM Overflow", _task->worker_id());
- }
}
}
};
@@ -2156,11 +2029,6 @@
void do_void() {
do {
- if (_cm->verbose_high()) {
- gclog_or_tty->print_cr("\t[%u] Drain: Calling do_marking_step - serial: %s",
- _task->worker_id(), BOOL_TO_STR(_is_serial));
- }
-
// We call CMTask::do_marking_step() to completely drain the local
// and global marking stacks of entries pushed by the 'keep alive'
// oop closure (an instance of G1CMKeepAliveAndDrainClosure above).
@@ -2436,7 +2304,7 @@
// circumspect about treating the argument as an object.
void do_entry(void* entry) const {
_task->increment_refs_reached();
- HeapRegion* hr = _g1h->heap_region_containing_raw(entry);
+ HeapRegion* hr = _g1h->heap_region_containing(entry);
if (entry < hr->next_top_at_mark_start()) {
// Until we get here, we don't know whether entry refers to a valid
// object; it could instead have been a stale reference.
@@ -2586,32 +2454,9 @@
while (finger < _heap_end) {
assert(_g1h->is_in_g1_reserved(finger), "invariant");
- // Note on how this code handles humongous regions. In the
- // normal case the finger will reach the start of a "starts
- // humongous" (SH) region. Its end will either be the end of the
- // last "continues humongous" (CH) region in the sequence, or the
- // standard end of the SH region (if the SH is the only region in
- // the sequence). That way claim_region() will skip over the CH
- // regions. However, there is a subtle race between a CM thread
- // executing this method and a mutator thread doing a humongous
- // object allocation. The two are not mutually exclusive as the CM
- // thread does not need to hold the Heap_lock when it gets
- // here. So there is a chance that claim_region() will come across
- // a free region that's in the progress of becoming a SH or a CH
- // region. In the former case, it will either
- // a) Miss the update to the region's end, in which case it will
- // visit every subsequent CH region, will find their bitmaps
- // empty, and do nothing, or
- // b) Will observe the update of the region's end (in which case
- // it will skip the subsequent CH regions).
- // If it comes across a region that suddenly becomes CH, the
- // scenario will be similar to b). So, the race between
- // claim_region() and a humongous object allocation might force us
- // to do a bit of unnecessary work (due to some unnecessary bitmap
- // iterations) but it should not introduce and correctness issues.
- HeapRegion* curr_region = _g1h->heap_region_containing_raw(finger);
-
- // Above heap_region_containing_raw may return NULL as we always scan claim
+ HeapRegion* curr_region = _g1h->heap_region_containing(finger);
+
+ // Above heap_region_containing may return NULL as we always scan claim
// until the end of the heap. In this case, just jump to the next region.
HeapWord* end = curr_region != NULL ? curr_region->end() : finger + HeapRegion::GrainWords;
@@ -2622,55 +2467,21 @@
HeapWord* bottom = curr_region->bottom();
HeapWord* limit = curr_region->next_top_at_mark_start();
- if (verbose_low()) {
- gclog_or_tty->print_cr("[%u] curr_region = " PTR_FORMAT " "
- "[" PTR_FORMAT ", " PTR_FORMAT "), "
- "limit = " PTR_FORMAT,
- worker_id, p2i(curr_region), p2i(bottom), p2i(end), p2i(limit));
- }
-
// notice that _finger == end cannot be guaranteed here since,
// someone else might have moved the finger even further
assert(_finger >= end, "the finger should have moved forward");
- if (verbose_low()) {
- gclog_or_tty->print_cr("[%u] we were successful with region = "
- PTR_FORMAT, worker_id, p2i(curr_region));
- }
-
if (limit > bottom) {
- if (verbose_low()) {
- gclog_or_tty->print_cr("[%u] region " PTR_FORMAT " is not empty, "
- "returning it ", worker_id, p2i(curr_region));
- }
return curr_region;
} else {
assert(limit == bottom,
"the region limit should be at bottom");
- if (verbose_low()) {
- gclog_or_tty->print_cr("[%u] region " PTR_FORMAT " is empty, "
- "returning NULL", worker_id, p2i(curr_region));
- }
// we return NULL and the caller should try calling
// claim_region() again.
return NULL;
}
} else {
assert(_finger > finger, "the finger should have moved forward");
- if (verbose_low()) {
- if (curr_region == NULL) {
- gclog_or_tty->print_cr("[%u] found uncommitted region, moving finger, "
- "global finger = " PTR_FORMAT ", "
- "our finger = " PTR_FORMAT,
- worker_id, p2i(_finger), p2i(finger));
- } else {
- gclog_or_tty->print_cr("[%u] somebody else moved the finger, "
- "global finger = " PTR_FORMAT ", "
- "our finger = " PTR_FORMAT,
- worker_id, p2i(_finger), p2i(finger));
- }
- }
-
// read it again
finger = _finger;
}
@@ -2721,16 +2532,9 @@
// Verify the global finger
HeapWord* global_finger = finger();
if (global_finger != NULL && global_finger < _heap_end) {
- // The global finger always points to a heap region boundary. We
- // use heap_region_containing_raw() to get the containing region
- // given that the global finger could be pointing to a free region
- // which subsequently becomes continues humongous. If that
- // happens, heap_region_containing() will return the bottom of the
- // corresponding starts humongous region and the check below will
- // not hold any more.
// Since we always iterate over all regions, we might get a NULL HeapRegion
// here.
- HeapRegion* global_hr = _g1h->heap_region_containing_raw(global_finger);
+ HeapRegion* global_hr = _g1h->heap_region_containing(global_finger);
guarantee(global_hr == NULL || global_finger == global_hr->bottom(),
"global finger: " PTR_FORMAT " region: " HR_FORMAT,
p2i(global_finger), HR_FORMAT_PARAMS(global_hr));
@@ -2743,7 +2547,7 @@
HeapWord* task_finger = task->finger();
if (task_finger != NULL && task_finger < _heap_end) {
// See above note on the global finger verification.
- HeapRegion* task_hr = _g1h->heap_region_containing_raw(task_finger);
+ HeapRegion* task_hr = _g1h->heap_region_containing(task_finger);
guarantee(task_hr == NULL || task_finger == task_hr->bottom() ||
!task_hr->in_collection_set(),
"task finger: " PTR_FORMAT " region: " HR_FORMAT,
@@ -2771,17 +2575,6 @@
_cm_card_bm(cm_card_bm), _max_worker_id(max_worker_id) { }
bool doHeapRegion(HeapRegion* hr) {
- if (hr->is_continues_humongous()) {
- // We will ignore these here and process them when their
- // associated "starts humongous" region is processed.
- // Note that we cannot rely on their associated
- // "starts humongous" region to have their bit set to 1
- // since, due to the region chunking in the parallel region
- // iteration, a "continues humongous" region might be visited
- // before its associated "starts humongous".
- return false;
- }
-
HeapWord* start = hr->bottom();
HeapWord* limit = hr->next_top_at_mark_start();
HeapWord* end = hr->end();
@@ -2926,7 +2719,7 @@
}
void ConcurrentMark::print_stats() {
- if (verbose_stats()) {
+ if (G1MarkingVerboseLevel > 0) {
gclog_or_tty->print_cr("---------------------------------------------------------------------");
for (size_t i = 0; i < _active_tasks; ++i) {
_tasks[i]->print_stats();
@@ -3038,18 +2831,6 @@
}
}
-#ifndef PRODUCT
-// for debugging purposes
-void ConcurrentMark::print_finger() {
- gclog_or_tty->print_cr("heap [" PTR_FORMAT ", " PTR_FORMAT "), global finger = " PTR_FORMAT,
- p2i(_heap_start), p2i(_heap_end), p2i(_finger));
- for (uint i = 0; i < _max_worker_id; ++i) {
- gclog_or_tty->print(" %u: " PTR_FORMAT, i, p2i(_tasks[i]->finger()));
- }
- gclog_or_tty->cr();
-}
-#endif
-
// Closure for iteration over bitmaps
class CMBitMapClosure : public BitMapClosure {
private:
@@ -3066,8 +2847,6 @@
HeapWord* addr = _nextMarkBitMap->offsetToHeapWord(offset);
assert(_nextMarkBitMap->isMarked(addr), "invariant");
assert( addr < _cm->finger(), "invariant");
-
- statsOnly( _task->increase_objs_found_on_bitmap() );
assert(addr >= _task->finger(), "invariant");
// We move that task's local finger along.
@@ -3103,14 +2882,6 @@
void CMTask::setup_for_region(HeapRegion* hr) {
assert(hr != NULL,
"claim_region() should have filtered out NULL regions");
- assert(!hr->is_continues_humongous(),
- "claim_region() should have filtered out continues humongous regions");
-
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] setting up for region " PTR_FORMAT,
- _worker_id, p2i(hr));
- }
-
_curr_region = hr;
_finger = hr->bottom();
update_region_limit();
@@ -3122,11 +2893,6 @@
HeapWord* limit = hr->next_top_at_mark_start();
if (limit == bottom) {
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] found an empty region "
- "[" PTR_FORMAT ", " PTR_FORMAT ")",
- _worker_id, p2i(bottom), p2i(limit));
- }
// The region was collected underneath our feet.
// We set the finger to bottom to ensure that the bitmap
// iteration that will follow this will not do anything.
@@ -3155,10 +2921,6 @@
void CMTask::giveup_current_region() {
assert(_curr_region != NULL, "invariant");
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] giving up region " PTR_FORMAT,
- _worker_id, p2i(_curr_region));
- }
clear_region_fields();
}
@@ -3181,11 +2943,6 @@
void CMTask::reset(CMBitMap* nextMarkBitMap) {
guarantee(nextMarkBitMap != NULL, "invariant");
-
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] resetting", _worker_id);
- }
-
_nextMarkBitMap = nextMarkBitMap;
clear_region_fields();
@@ -3193,30 +2950,6 @@
_elapsed_time_ms = 0.0;
_termination_time_ms = 0.0;
_termination_start_time_ms = 0.0;
-
-#if _MARKING_STATS_
- _aborted = 0;
- _aborted_overflow = 0;
- _aborted_cm_aborted = 0;
- _aborted_yield = 0;
- _aborted_timed_out = 0;
- _aborted_satb = 0;
- _aborted_termination = 0;
- _steal_attempts = 0;
- _steals = 0;
- _local_pushes = 0;
- _local_pops = 0;
- _local_max_size = 0;
- _objs_scanned = 0;
- _global_pushes = 0;
- _global_pops = 0;
- _global_max_size = 0;
- _global_transfers_to = 0;
- _global_transfers_from = 0;
- _regions_claimed = 0;
- _objs_found_on_bitmap = 0;
- _satb_buffers_processed = 0;
-#endif // _MARKING_STATS_
}
bool CMTask::should_exit_termination() {
@@ -3257,42 +2990,16 @@
// (2) If marking has been aborted for Full GC, then we also abort.
if (_cm->has_aborted()) {
set_has_aborted();
- statsOnly( ++_aborted_cm_aborted );
return;
}
double curr_time_ms = os::elapsedVTime() * 1000.0;
- // (3) If marking stats are enabled, then we update the step history.
-#if _MARKING_STATS_
- if (_words_scanned >= _words_scanned_limit) {
- ++_clock_due_to_scanning;
- }
- if (_refs_reached >= _refs_reached_limit) {
- ++_clock_due_to_marking;
- }
-
- double last_interval_ms = curr_time_ms - _interval_start_time_ms;
- _interval_start_time_ms = curr_time_ms;
- _all_clock_intervals_ms.add(last_interval_ms);
-
- if (_cm->verbose_medium()) {
- gclog_or_tty->print_cr("[%u] regular clock, interval = %1.2lfms, "
- "scanned = " SIZE_FORMAT "%s, refs reached = " SIZE_FORMAT "%s",
- _worker_id, last_interval_ms,
- _words_scanned,
- (_words_scanned >= _words_scanned_limit) ? " (*)" : "",
- _refs_reached,
- (_refs_reached >= _refs_reached_limit) ? " (*)" : "");
- }
-#endif // _MARKING_STATS_
-
// (4) We check whether we should yield. If we have to, then we abort.
if (SuspendibleThreadSet::should_yield()) {
// We should yield. To do this we abort the task. The caller is
// responsible for yielding.
set_has_aborted();
- statsOnly( ++_aborted_yield );
return;
}
@@ -3302,7 +3009,6 @@
if (elapsed_time_ms > _time_target_ms) {
set_has_aborted();
_has_timed_out = true;
- statsOnly( ++_aborted_timed_out );
return;
}
@@ -3310,14 +3016,9 @@
// buffers available for processing. If there are, we abort.
SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
if (!_draining_satb_buffers && satb_mq_set.process_completed_buffers()) {
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] aborting to deal with pending SATB buffers",
- _worker_id);
- }
// we do need to process SATB buffers, we'll abort and restart
// the marking task to do so
set_has_aborted();
- statsOnly( ++_aborted_satb );
return;
}
}
@@ -3336,10 +3037,6 @@
// entries to/from the global stack). It basically tries to decrease the
// scanning limit so that the clock is called earlier.
- if (_cm->verbose_medium()) {
- gclog_or_tty->print_cr("[%u] decreasing limits", _worker_id);
- }
-
_words_scanned_limit = _real_words_scanned_limit -
3 * words_scanned_period / 4;
_refs_reached_limit = _real_refs_reached_limit -
@@ -3361,26 +3058,8 @@
if (n > 0) {
// we popped at least one entry from the local queue
- statsOnly( ++_global_transfers_to; _local_pops += n );
-
if (!_cm->mark_stack_push(buffer, n)) {
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] aborting due to global stack overflow",
- _worker_id);
- }
set_has_aborted();
- } else {
- // the transfer was successful
-
- if (_cm->verbose_medium()) {
- gclog_or_tty->print_cr("[%u] pushed %d entries to the global stack",
- _worker_id, n);
- }
- statsOnly( size_t tmp_size = _cm->mark_stack_size();
- if (tmp_size > _global_max_size) {
- _global_max_size = tmp_size;
- }
- _global_pushes += n );
}
}
@@ -3398,24 +3077,12 @@
"we should not pop more than the given limit");
if (n > 0) {
// yes, we did actually pop at least one entry
-
- statsOnly( ++_global_transfers_from; _global_pops += n );
- if (_cm->verbose_medium()) {
- gclog_or_tty->print_cr("[%u] popped %d entries from the global stack",
- _worker_id, n);
- }
for (int i = 0; i < n; ++i) {
bool success = _task_queue->push(buffer[i]);
// We only call this when the local queue is empty or under a
// given target limit. So, we do not expect this push to fail.
assert(success, "invariant");
}
-
- statsOnly( size_t tmp_size = (size_t)_task_queue->size();
- if (tmp_size > _local_max_size) {
- _local_max_size = tmp_size;
- }
- _local_pushes += n );
}
// this operation was quite expensive, so decrease the limits
@@ -3436,21 +3103,9 @@
}
if (_task_queue->size() > target_size) {
- if (_cm->verbose_high()) {
- gclog_or_tty->print_cr("[%u] draining local queue, target size = " SIZE_FORMAT,
- _worker_id, target_size);
- }
-
oop obj;
bool ret = _task_queue->pop_local(obj);
while (ret) {
- statsOnly( ++_local_pops );
-
- if (_cm->verbose_high()) {
- gclog_or_tty->print_cr("[%u] popped " PTR_FORMAT, _worker_id,
- p2i((void*) obj));
- }
-
assert(_g1h->is_in_g1_reserved((HeapWord*) obj), "invariant" );
assert(!_g1h->is_on_master_free_list(
_g1h->heap_region_containing((HeapWord*) obj)), "invariant");
@@ -3463,11 +3118,6 @@
ret = _task_queue->pop_local(obj);
}
}
-
- if (_cm->verbose_high()) {
- gclog_or_tty->print_cr("[%u] drained local queue, size = %u",
- _worker_id, _task_queue->size());
- }
}
}
@@ -3492,20 +3142,10 @@
}
if (_cm->mark_stack_size() > target_size) {
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] draining global_stack, target size " SIZE_FORMAT,
- _worker_id, target_size);
- }
-
while (!has_aborted() && _cm->mark_stack_size() > target_size) {
get_entries_from_global_stack();
drain_local_queue(partially);
}
-
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] drained global stack, size = " SIZE_FORMAT,
- _worker_id, _cm->mark_stack_size());
- }
}
}
@@ -3529,10 +3169,6 @@
// until we run out of buffers or we need to abort.
while (!has_aborted() &&
satb_mq_set.apply_closure_to_completed_buffer(&satb_cl)) {
- if (_cm->verbose_medium()) {
- gclog_or_tty->print_cr("[%u] processed an SATB buffer", _worker_id);
- }
- statsOnly( ++_satb_buffers_processed );
regular_clock_call();
}
@@ -3557,34 +3193,6 @@
_step_times_ms.sd());
gclog_or_tty->print_cr(" max = %1.2lfms, total = %1.2lfms",
_step_times_ms.maximum(), _step_times_ms.sum());
-
-#if _MARKING_STATS_
- gclog_or_tty->print_cr(" Clock Intervals (cum): num = %d, avg = %1.2lfms, sd = %1.2lfms",
- _all_clock_intervals_ms.num(), _all_clock_intervals_ms.avg(),
- _all_clock_intervals_ms.sd());
- gclog_or_tty->print_cr(" max = %1.2lfms, total = %1.2lfms",
- _all_clock_intervals_ms.maximum(),
- _all_clock_intervals_ms.sum());
- gclog_or_tty->print_cr(" Clock Causes (cum): scanning = " SIZE_FORMAT ", marking = " SIZE_FORMAT,
- _clock_due_to_scanning, _clock_due_to_marking);
- gclog_or_tty->print_cr(" Objects: scanned = " SIZE_FORMAT ", found on the bitmap = " SIZE_FORMAT,
- _objs_scanned, _objs_found_on_bitmap);
- gclog_or_tty->print_cr(" Local Queue: pushes = " SIZE_FORMAT ", pops = " SIZE_FORMAT ", max size = " SIZE_FORMAT,
- _local_pushes, _local_pops, _local_max_size);
- gclog_or_tty->print_cr(" Global Stack: pushes = " SIZE_FORMAT ", pops = " SIZE_FORMAT ", max size = " SIZE_FORMAT,
- _global_pushes, _global_pops, _global_max_size);
- gclog_or_tty->print_cr(" transfers to = " SIZE_FORMAT ", transfers from = " SIZE_FORMAT,
- _global_transfers_to,_global_transfers_from);
- gclog_or_tty->print_cr(" Regions: claimed = " SIZE_FORMAT, _regions_claimed);
- gclog_or_tty->print_cr(" SATB buffers: processed = " SIZE_FORMAT, _satb_buffers_processed);
- gclog_or_tty->print_cr(" Steals: attempts = " SIZE_FORMAT ", successes = " SIZE_FORMAT,
- _steal_attempts, _steals);
- gclog_or_tty->print_cr(" Aborted: " SIZE_FORMAT ", due to", _aborted);
- gclog_or_tty->print_cr(" overflow: " SIZE_FORMAT ", global abort: " SIZE_FORMAT ", yield: " SIZE_FORMAT,
- _aborted_overflow, _aborted_cm_aborted, _aborted_yield);
- gclog_or_tty->print_cr(" time out: " SIZE_FORMAT ", SATB: " SIZE_FORMAT ", termination: " SIZE_FORMAT,
- _aborted_timed_out, _aborted_satb, _aborted_termination);
-#endif // _MARKING_STATS_
}
bool ConcurrentMark::try_stealing(uint worker_id, int* hash_seed, oop& obj) {
@@ -3727,7 +3335,6 @@
_claimed = true;
_start_time_ms = os::elapsedVTime() * 1000.0;
- statsOnly( _interval_start_time_ms = _start_time_ms );
// If do_stealing is true then do_marking_step will attempt to
// steal work from the other CMTasks. It only makes sense to
@@ -3751,12 +3358,6 @@
++_calls;
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] >>>>>>>>>> START, call = %d, "
- "target = %1.2lfms >>>>>>>>>>",
- _worker_id, _calls, _time_target_ms);
- }
-
// Set up the bitmap and oop closures. Anything that uses them is
// eventually called from this method, so it is OK to allocate these
// statically.
@@ -3801,14 +3402,6 @@
// fresh region, _finger points to start().
MemRegion mr = MemRegion(_finger, _region_limit);
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] we're scanning part "
- "[" PTR_FORMAT ", " PTR_FORMAT ") "
- "of region " HR_FORMAT,
- _worker_id, p2i(_finger), p2i(_region_limit),
- HR_FORMAT_PARAMS(_curr_region));
- }
-
assert(!_curr_region->is_humongous() || mr.start() == _curr_region->bottom(),
"humongous regions should go around loop once only");
@@ -3881,20 +3474,9 @@
assert(_curr_region == NULL, "invariant");
assert(_finger == NULL, "invariant");
assert(_region_limit == NULL, "invariant");
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] trying to claim a new region", _worker_id);
- }
HeapRegion* claimed_region = _cm->claim_region(_worker_id);
if (claimed_region != NULL) {
// Yes, we managed to claim one
- statsOnly( ++_regions_claimed );
-
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] we successfully claimed "
- "region " PTR_FORMAT,
- _worker_id, p2i(claimed_region));
- }
-
setup_for_region(claimed_region);
assert(_curr_region == claimed_region, "invariant");
}
@@ -3917,11 +3499,6 @@
// tasks might be pushing objects to it concurrently.
assert(_cm->out_of_regions(),
"at this point we should be out of regions");
-
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] all regions claimed", _worker_id);
- }
-
// Try to reduce the number of available SATB buffers so that
// remark has less work to do.
drain_satb_buffers();
@@ -3941,23 +3518,9 @@
// tasks might be pushing objects to it concurrently.
assert(_cm->out_of_regions() && _task_queue->size() == 0,
"only way to reach here");
-
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] starting to steal", _worker_id);
- }
-
while (!has_aborted()) {
oop obj;
- statsOnly( ++_steal_attempts );
-
if (_cm->try_stealing(_worker_id, &_hash_seed, obj)) {
- if (_cm->verbose_medium()) {
- gclog_or_tty->print_cr("[%u] stolen " PTR_FORMAT " successfully",
- _worker_id, p2i((void*) obj));
- }
-
- statsOnly( ++_steals );
-
assert(_nextMarkBitMap->isMarked((HeapWord*) obj),
"any stolen object should be marked");
scan_object(obj);
@@ -3989,11 +3552,6 @@
// Separated the asserts so that we know which one fires.
assert(_cm->out_of_regions(), "only way to reach here");
assert(_task_queue->size() == 0, "only way to reach here");
-
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] starting termination protocol", _worker_id);
- }
-
_termination_start_time_ms = os::elapsedVTime() * 1000.0;
// The CMTask class also extends the TerminatorTerminator class,
@@ -4028,21 +3586,10 @@
guarantee(_task_queue->size() == 0, "only way to reach here");
guarantee(!_cm->has_overflown(), "only way to reach here");
guarantee(!_cm->mark_stack_overflow(), "only way to reach here");
-
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] all tasks terminated", _worker_id);
- }
} else {
// Apparently there's more work to do. Let's abort this task. It
// will restart it and we can hopefully find more things to do.
-
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] apparently there is more work to do",
- _worker_id);
- }
-
set_has_aborted();
- statsOnly( ++_aborted_termination );
}
}
@@ -4057,9 +3604,6 @@
if (has_aborted()) {
// The task was aborted for some reason.
-
- statsOnly( ++_aborted );
-
if (_has_timed_out) {
double diff_ms = elapsed_time_ms - _time_target_ms;
// Keep statistics of how well we did with respect to hitting
@@ -4076,10 +3620,6 @@
// what they are doing and re-initialize in a safe manner. We
// will achieve this with the use of two barrier sync points.
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] detected overflow", _worker_id);
- }
-
if (!is_serial) {
// We only need to enter the sync barrier if being called
// from a parallel context
@@ -4091,8 +3631,6 @@
// task 0 will clear the global data structures.
}
- statsOnly( ++_aborted_overflow );
-
// We clear the local state of this task...
clear_region_fields();
@@ -4104,22 +3642,6 @@
// marking, everything has been re-initialized and we're
// ready to restart.
}
-
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] <<<<<<<<<< ABORTING, target = %1.2lfms, "
- "elapsed = %1.2lfms <<<<<<<<<<",
- _worker_id, _time_target_ms, elapsed_time_ms);
- if (_cm->has_aborted()) {
- gclog_or_tty->print_cr("[%u] ========== MARKING ABORTED ==========",
- _worker_id);
- }
- }
- } else {
- if (_cm->verbose_low()) {
- gclog_or_tty->print_cr("[%u] <<<<<<<<<< FINISHED, target = %1.2lfms, "
- "elapsed = %1.2lfms <<<<<<<<<<",
- _worker_id, _time_target_ms, elapsed_time_ms);
- }
}
_claimed = false;
@@ -4143,9 +3665,6 @@
guarantee(task_queue != NULL, "invariant");
guarantee(task_queues != NULL, "invariant");
- statsOnly( _clock_due_to_scanning = 0;
- _clock_due_to_marking = 0 );
-
_marking_step_diffs_ms.add(0.5);
}
--- a/hotspot/src/share/vm/gc/g1/concurrentMark.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/concurrentMark.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -244,30 +244,6 @@
bool should_force() PRODUCT_RETURN_( return false; );
};
-// this will enable a variety of different statistics per GC task
-#define _MARKING_STATS_ 0
-// this will enable the higher verbose levels
-#define _MARKING_VERBOSE_ 0
-
-#if _MARKING_STATS_
-#define statsOnly(statement) \
-do { \
- statement ; \
-} while (0)
-#else // _MARKING_STATS_
-#define statsOnly(statement) \
-do { \
-} while (0)
-#endif // _MARKING_STATS_
-
-typedef enum {
- no_verbose = 0, // verbose turned off
- stats_verbose, // only prints stats at the end of marking
- low_verbose, // low verbose, mostly per region and per major event
- medium_verbose, // a bit more detailed than low
- high_verbose // per object verbose
-} CMVerboseLevel;
-
class YoungList;
// Root Regions are regions that are not empty at the beginning of a
@@ -415,9 +391,6 @@
// time of remark.
volatile bool _concurrent_marking_in_progress;
- // Verbose level
- CMVerboseLevel _verbose_level;
-
// All of these times are in ms
NumberSeq _init_times;
NumberSeq _remark_times;
@@ -746,31 +719,12 @@
bool has_aborted() { return _has_aborted; }
- // This prints the global/local fingers. It is used for debugging.
- NOT_PRODUCT(void print_finger();)
-
void print_summary_info();
void print_worker_threads_on(outputStream* st) const;
void print_on_error(outputStream* st) const;
- // The following indicate whether a given verbose level has been
- // set. Notice that anything above stats is conditional to
- // _MARKING_VERBOSE_ having been set to 1
- bool verbose_stats() {
- return _verbose_level >= stats_verbose;
- }
- bool verbose_low() {
- return _MARKING_VERBOSE_ && _verbose_level >= low_verbose;
- }
- bool verbose_medium() {
- return _MARKING_VERBOSE_ && _verbose_level >= medium_verbose;
- }
- bool verbose_high() {
- return _MARKING_VERBOSE_ && _verbose_level >= high_verbose;
- }
-
// Liveness counting
// Utility routine to set an exclusive range of cards on the given
@@ -818,16 +772,13 @@
size_t* marked_bytes_array,
BitMap* task_card_bm);
- // Counts the given memory region in the task/worker counting
- // data structures for the given worker id.
- inline void count_region(MemRegion mr, HeapRegion* hr, uint worker_id);
-
// Counts the given object in the given task/worker counting
// data structures.
inline void count_object(oop obj,
HeapRegion* hr,
size_t* marked_bytes_array,
- BitMap* task_card_bm);
+ BitMap* task_card_bm,
+ size_t word_size);
// Attempts to mark the given object and, if successful, counts
// the object in the given task/worker counting structures.
@@ -969,43 +920,6 @@
size_t* _marked_bytes_array;
BitMap* _card_bm;
- // LOTS of statistics related with this task
-#if _MARKING_STATS_
- NumberSeq _all_clock_intervals_ms;
- double _interval_start_time_ms;
-
- size_t _aborted;
- size_t _aborted_overflow;
- size_t _aborted_cm_aborted;
- size_t _aborted_yield;
- size_t _aborted_timed_out;
- size_t _aborted_satb;
- size_t _aborted_termination;
-
- size_t _steal_attempts;
- size_t _steals;
-
- size_t _clock_due_to_marking;
- size_t _clock_due_to_scanning;
-
- size_t _local_pushes;
- size_t _local_pops;
- size_t _local_max_size;
- size_t _objs_scanned;
-
- size_t _global_pushes;
- size_t _global_pops;
- size_t _global_max_size;
-
- size_t _global_transfers_to;
- size_t _global_transfers_from;
-
- size_t _regions_claimed;
- size_t _objs_found_on_bitmap;
-
- size_t _satb_buffers_processed;
-#endif // _MARKING_STATS_
-
// it updates the local fields after this task has claimed
// a new region to scan
void setup_for_region(HeapRegion* hr);
@@ -1139,10 +1053,6 @@
// it prints statistics associated with this task
void print_stats();
-
-#if _MARKING_STATS_
- void increase_objs_found_on_bitmap() { ++_objs_found_on_bitmap; }
-#endif // _MARKING_STATS_
};
// Class that's used to to print out per-region liveness
--- a/hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -89,9 +89,7 @@
size_t region_size_bytes = mr.byte_size();
uint index = hr->hrm_index();
- assert(!hr->is_continues_humongous(), "should not be HC region");
assert(hr == g1h->heap_region_containing(start), "sanity");
- assert(hr == g1h->heap_region_containing(mr.last()), "sanity");
assert(marked_bytes_array != NULL, "pre-condition");
assert(task_card_bm != NULL, "pre-condition");
@@ -116,23 +114,23 @@
set_card_bitmap_range(task_card_bm, start_idx, end_idx, false /* is_par */);
}
-// Counts the given memory region in the task/worker counting
-// data structures for the given worker id.
-inline void ConcurrentMark::count_region(MemRegion mr,
- HeapRegion* hr,
- uint worker_id) {
- size_t* marked_bytes_array = count_marked_bytes_array_for(worker_id);
- BitMap* task_card_bm = count_card_bitmap_for(worker_id);
- count_region(mr, hr, marked_bytes_array, task_card_bm);
-}
-
// Counts the given object in the given task/worker counting data structures.
inline void ConcurrentMark::count_object(oop obj,
HeapRegion* hr,
size_t* marked_bytes_array,
- BitMap* task_card_bm) {
- MemRegion mr((HeapWord*)obj, obj->size());
- count_region(mr, hr, marked_bytes_array, task_card_bm);
+ BitMap* task_card_bm,
+ size_t word_size) {
+ assert(!hr->is_continues_humongous(), "Cannot enter count_object with continues humongous");
+ if (!hr->is_starts_humongous()) {
+ MemRegion mr((HeapWord*)obj, word_size);
+ count_region(mr, hr, marked_bytes_array, task_card_bm);
+ } else {
+ do {
+ MemRegion mr(hr->bottom(), hr->top());
+ count_region(mr, hr, marked_bytes_array, task_card_bm);
+ hr = _g1h->next_region_in_humongous(hr);
+ } while (hr != NULL);
+ }
}
// Attempts to mark the given object and, if successful, counts
@@ -141,10 +139,9 @@
HeapRegion* hr,
size_t* marked_bytes_array,
BitMap* task_card_bm) {
- HeapWord* addr = (HeapWord*)obj;
- if (_nextMarkBitMap->parMark(addr)) {
+ if (_nextMarkBitMap->parMark((HeapWord*)obj)) {
// Update the task specific count data for the object.
- count_object(obj, hr, marked_bytes_array, task_card_bm);
+ count_object(obj, hr, marked_bytes_array, task_card_bm, obj->size());
return true;
}
return false;
@@ -157,10 +154,10 @@
size_t word_size,
HeapRegion* hr,
uint worker_id) {
- HeapWord* addr = (HeapWord*)obj;
- if (_nextMarkBitMap->parMark(addr)) {
- MemRegion mr(addr, word_size);
- count_region(mr, hr, worker_id);
+ if (_nextMarkBitMap->parMark((HeapWord*)obj)) {
+ size_t* marked_bytes_array = count_marked_bytes_array_for(worker_id);
+ BitMap* task_card_bm = count_card_bitmap_for(worker_id);
+ count_object(obj, hr, marked_bytes_array, task_card_bm, word_size);
return true;
}
return false;
@@ -242,19 +239,9 @@
assert(!_g1h->is_obj_ill(obj), "invariant");
assert(_nextMarkBitMap->isMarked(objAddr), "invariant");
- if (_cm->verbose_high()) {
- gclog_or_tty->print_cr("[%u] pushing " PTR_FORMAT, _worker_id, p2i((void*) obj));
- }
-
if (!_task_queue->push(obj)) {
// The local task queue looks full. We need to push some entries
// to the global stack.
-
- if (_cm->verbose_medium()) {
- gclog_or_tty->print_cr("[%u] task queue overflow, "
- "moving entries to the global stack",
- _worker_id);
- }
move_entries_to_global_stack();
// this should succeed since, even if we overflow the global
@@ -263,12 +250,6 @@
bool success = _task_queue->push(obj);
assert(success, "invariant");
}
-
- statsOnly( size_t tmp_size = (size_t)_task_queue->size();
- if (tmp_size > _local_max_size) {
- _local_max_size = tmp_size;
- }
- ++_local_pushes );
}
inline bool CMTask::is_below_finger(oop obj, HeapWord* global_finger) const {
@@ -306,18 +287,12 @@
assert(scan || obj->is_typeArray(), "Skipping scan of grey non-typeArray");
assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant");
- if (_cm->verbose_high()) {
- gclog_or_tty->print_cr("[%u] processing grey object " PTR_FORMAT,
- _worker_id, p2i((void*) obj));
- }
-
size_t obj_size = obj->size();
_words_scanned += obj_size;
if (scan) {
obj->oop_iterate(_cm_oop_closure);
}
- statsOnly( ++_objs_scanned );
check_limits();
}
@@ -325,12 +300,6 @@
inline void CMTask::make_reference_grey(oop obj, HeapRegion* hr) {
if (_cm->par_mark_and_count(obj, hr, _marked_bytes_array, _card_bm)) {
-
- if (_cm->verbose_high()) {
- gclog_or_tty->print_cr("[%u] marked object " PTR_FORMAT,
- _worker_id, p2i(obj));
- }
-
// No OrderAccess:store_load() is needed. It is implicit in the
// CAS done in CMBitMap::parMark() call in the routine above.
HeapWord* global_finger = _cm->finger();
@@ -362,13 +331,6 @@
// references, and the metadata is built-in.
process_grey_object<false>(obj);
} else {
- if (_cm->verbose_high()) {
- gclog_or_tty->print_cr("[%u] below a finger (local: " PTR_FORMAT
- ", global: " PTR_FORMAT ") pushing "
- PTR_FORMAT " on mark stack",
- _worker_id, p2i(_finger),
- p2i(global_finger), p2i(obj));
- }
push(obj);
}
}
@@ -376,11 +338,6 @@
}
inline void CMTask::deal_with_reference(oop obj) {
- if (_cm->verbose_high()) {
- gclog_or_tty->print_cr("[%u] we're dealing with reference = " PTR_FORMAT,
- _worker_id, p2i((void*) obj));
- }
-
increment_refs_reached();
HeapWord* objAddr = (HeapWord*) obj;
@@ -391,7 +348,7 @@
// Only get the containing region if the object is not marked on the
// bitmap (otherwise, it's a waste of time since we won't do
// anything with it).
- HeapRegion* hr = _g1h->heap_region_containing_raw(obj);
+ HeapRegion* hr = _g1h->heap_region_containing(obj);
if (!hr->obj_allocated_since_next_marking(obj)) {
make_reference_grey(obj, hr);
}
@@ -411,7 +368,7 @@
assert(obj != NULL, "pre-condition");
HeapWord* addr = (HeapWord*) obj;
if (hr == NULL) {
- hr = _g1h->heap_region_containing_raw(addr);
+ hr = _g1h->heap_region_containing(addr);
} else {
assert(hr->is_in(addr), "pre-condition");
}
@@ -420,16 +377,6 @@
// header it's impossible to get back a HC region.
assert(!hr->is_continues_humongous(), "sanity");
- // We cannot assert that word_size == obj->size() given that obj
- // might not be in a consistent state (another thread might be in
- // the process of copying it). So the best thing we can do is to
- // assert that word_size is under an upper bound which is its
- // containing region's capacity.
- assert(word_size * HeapWordSize <= hr->capacity(),
- "size: " SIZE_FORMAT " capacity: " SIZE_FORMAT " " HR_FORMAT,
- word_size * HeapWordSize, hr->capacity(),
- HR_FORMAT_PARAMS(hr));
-
if (addr < hr->next_top_at_mark_start()) {
if (!_nextMarkBitMap->isMarked(addr)) {
par_mark_and_count(obj, word_size, hr, worker_id);
--- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -32,6 +32,18 @@
#include "runtime/safepoint.hpp"
#include "runtime/thread.inline.hpp"
+DirtyCardQueue::DirtyCardQueue(DirtyCardQueueSet* qset, bool permanent) :
+ // Dirty card queues are always active, so we create them with their
+ // active field set to true.
+ PtrQueue(qset, permanent, true /* active */)
+{ }
+
+DirtyCardQueue::~DirtyCardQueue() {
+ if (!is_permanent()) {
+ flush();
+ }
+}
+
bool DirtyCardQueue::apply_closure(CardTableEntryClosure* cl,
bool consume,
uint worker_i) {
@@ -40,7 +52,9 @@
res = apply_closure_to_buffer(cl, _buf, _index, _sz,
consume,
worker_i);
- if (res && consume) _index = _sz;
+ if (res && consume) {
+ _index = _sz;
+ }
}
return res;
}
@@ -51,27 +65,27 @@
bool consume,
uint worker_i) {
if (cl == NULL) return true;
- for (size_t i = index; i < sz; i += oopSize) {
- int ind = byte_index_to_index((int)i);
- jbyte* card_ptr = (jbyte*)buf[ind];
+ size_t limit = byte_index_to_index(sz);
+ for (size_t i = byte_index_to_index(index); i < limit; ++i) {
+ jbyte* card_ptr = static_cast<jbyte*>(buf[i]);
if (card_ptr != NULL) {
// Set the entry to null, so we don't do it again (via the test
// above) if we reconsider this buffer.
- if (consume) buf[ind] = NULL;
- if (!cl->do_card_ptr(card_ptr, worker_i)) return false;
+ if (consume) {
+ buf[i] = NULL;
+ }
+ if (!cl->do_card_ptr(card_ptr, worker_i)) {
+ return false;
+ }
}
}
return true;
}
-#ifdef _MSC_VER // the use of 'this' below gets a warning, make it go away
-#pragma warning( disable:4355 ) // 'this' : used in base member initializer list
-#endif // _MSC_VER
-
DirtyCardQueueSet::DirtyCardQueueSet(bool notify_when_complete) :
PtrQueueSet(notify_when_complete),
_mut_process_closure(NULL),
- _shared_dirty_card_queue(this, true /*perm*/),
+ _shared_dirty_card_queue(this, true /* permanent */),
_free_ids(NULL),
_processed_buffers_mut(0), _processed_buffers_rs_thread(0)
{
@@ -83,13 +97,19 @@
return (uint)os::processor_count();
}
-void DirtyCardQueueSet::initialize(CardTableEntryClosure* cl, Monitor* cbl_mon, Mutex* fl_lock,
+void DirtyCardQueueSet::initialize(CardTableEntryClosure* cl,
+ Monitor* cbl_mon,
+ Mutex* fl_lock,
int process_completed_threshold,
int max_completed_queue,
- Mutex* lock, PtrQueueSet* fl_owner) {
+ Mutex* lock,
+ DirtyCardQueueSet* fl_owner) {
_mut_process_closure = cl;
- PtrQueueSet::initialize(cbl_mon, fl_lock, process_completed_threshold,
- max_completed_queue, fl_owner);
+ PtrQueueSet::initialize(cbl_mon,
+ fl_lock,
+ process_completed_threshold,
+ max_completed_queue,
+ fl_owner);
set_buffer_size(G1UpdateBufferSize);
_shared_dirty_card_queue.set_lock(lock);
_free_ids = new FreeIdSet((int) num_par_ids(), _cbl_mon);
@@ -103,7 +123,7 @@
bool consume,
uint worker_i) {
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
- for(JavaThread* t = Threads::first(); t; t = t->next()) {
+ for (JavaThread* t = Threads::first(); t; t = t->next()) {
bool b = t->dirty_card_queue().apply_closure(cl, consume);
guarantee(b, "Should not be interrupted.");
}
@@ -160,8 +180,7 @@
}
-BufferNode*
-DirtyCardQueueSet::get_completed_buffer(int stop_at) {
+BufferNode* DirtyCardQueueSet::get_completed_buffer(int stop_at) {
BufferNode* nd = NULL;
MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
@@ -178,14 +197,13 @@
_n_completed_buffers--;
assert(_n_completed_buffers >= 0, "Invariant");
}
- debug_only(assert_completed_buffer_list_len_correct_locked());
+ DEBUG_ONLY(assert_completed_buffer_list_len_correct_locked());
return nd;
}
-bool DirtyCardQueueSet::
-apply_closure_to_completed_buffer_helper(CardTableEntryClosure* cl,
- uint worker_i,
- BufferNode* nd) {
+bool DirtyCardQueueSet::apply_closure_to_completed_buffer_helper(CardTableEntryClosure* cl,
+ uint worker_i,
+ BufferNode* nd) {
if (nd != NULL) {
void **buf = BufferNode::make_buffer_from_node(nd);
size_t index = nd->index();
@@ -259,7 +277,7 @@
}
_n_completed_buffers = 0;
_completed_buffers_tail = NULL;
- debug_only(assert_completed_buffer_list_len_correct_locked());
+ DEBUG_ONLY(assert_completed_buffer_list_len_correct_locked());
}
while (buffers_to_delete != NULL) {
BufferNode* nd = buffers_to_delete;
@@ -291,10 +309,11 @@
for (JavaThread* t = Threads::first(); t; t = t->next()) {
DirtyCardQueue& dcq = t->dirty_card_queue();
if (dcq.size() != 0) {
- void **buf = t->dirty_card_queue().get_buf();
+ void** buf = dcq.get_buf();
// We must NULL out the unused entries, then enqueue.
- for (size_t i = 0; i < t->dirty_card_queue().get_index(); i += oopSize) {
- buf[PtrQueue::byte_index_to_index((int)i)] = NULL;
+ size_t limit = dcq.byte_index_to_index(dcq.get_index());
+ for (size_t i = 0; i < limit; ++i) {
+ buf[i] = NULL;
}
enqueue_complete_buffer(dcq.get_buf(), dcq.get_index());
dcq.reinitialize();
--- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -29,6 +29,7 @@
#include "memory/allocation.hpp"
class FreeIdSet;
+class DirtyCardQueueSet;
// A closure class for processing card table entries. Note that we don't
// require these closure objects to be stack-allocated.
@@ -42,14 +43,11 @@
// A ptrQueue whose elements are "oops", pointers to object heads.
class DirtyCardQueue: public PtrQueue {
public:
- DirtyCardQueue(PtrQueueSet* qset_, bool perm = false) :
- // Dirty card queues are always active, so we create them with their
- // active field set to true.
- PtrQueue(qset_, perm, true /* active */) { }
+ DirtyCardQueue(DirtyCardQueueSet* qset, bool permanent = false);
// Flush before destroying; queue may be used to capture pending work while
// doing something else, with auto-flush on completion.
- ~DirtyCardQueue() { if (!is_permanent()) flush(); }
+ ~DirtyCardQueue();
// Process queue entries and release resources.
void flush() { flush_impl(); }
@@ -72,7 +70,6 @@
bool consume = true,
uint worker_i = 0);
void **get_buf() { return _buf;}
- void set_buf(void **buf) {_buf = buf;}
size_t get_index() { return _index;}
void reinitialize() { _buf = 0; _sz = 0; _index = 0;}
};
@@ -101,10 +98,13 @@
public:
DirtyCardQueueSet(bool notify_when_complete = true);
- void initialize(CardTableEntryClosure* cl, Monitor* cbl_mon, Mutex* fl_lock,
+ void initialize(CardTableEntryClosure* cl,
+ Monitor* cbl_mon,
+ Mutex* fl_lock,
int process_completed_threshold,
int max_completed_queue,
- Mutex* lock, PtrQueueSet* fl_owner = NULL);
+ Mutex* lock,
+ DirtyCardQueueSet* fl_owner = NULL);
// The number of parallel ids that can be claimed to allow collector or
// mutator threads to do card-processing work.
--- a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -110,9 +110,6 @@
if (_retained_old_gc_alloc_region != NULL) {
_retained_old_gc_alloc_region->record_retained_region();
}
-
- _g1h->alloc_buffer_stats(InCSetState::Young)->adjust_desired_plab_sz();
- _g1h->alloc_buffer_stats(InCSetState::Old)->adjust_desired_plab_sz();
}
void G1DefaultAllocator::abandon_gc_alloc_regions() {
--- a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -499,18 +499,14 @@
return _next_offset_threshold;
}
-void
-G1BlockOffsetArrayContigSpace::set_for_starts_humongous(HeapWord* new_top) {
- assert(new_top <= _end, "_end should have already been updated");
-
+void G1BlockOffsetArrayContigSpace::set_for_starts_humongous(HeapWord* obj_top) {
// The first BOT entry should have offset 0.
reset_bot();
- alloc_block(_bottom, new_top);
+ alloc_block(_bottom, obj_top);
}
#ifndef PRODUCT
-void
-G1BlockOffsetArrayContigSpace::print_on(outputStream* out) {
+void G1BlockOffsetArrayContigSpace::print_on(outputStream* out) {
G1BlockOffsetArray::print_on(out);
out->print_cr(" next offset threshold: " PTR_FORMAT, p2i(_next_offset_threshold));
out->print_cr(" next offset index: " SIZE_FORMAT, _next_offset_index);
--- a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -361,17 +361,18 @@
// implementation, that's true because NULL is represented as 0, and thus
// never exceeds the "_next_offset_threshold".
void alloc_block(HeapWord* blk_start, HeapWord* blk_end) {
- if (blk_end > _next_offset_threshold)
+ if (blk_end > _next_offset_threshold) {
alloc_block_work1(blk_start, blk_end);
+ }
}
void alloc_block(HeapWord* blk, size_t size) {
- alloc_block(blk, blk+size);
+ alloc_block(blk, blk+size);
}
HeapWord* block_start_unsafe(const void* addr);
HeapWord* block_start_unsafe_const(const void* addr) const;
- void set_for_starts_humongous(HeapWord* new_top);
+ void set_for_starts_humongous(HeapWord* obj_top);
virtual void print_on(outputStream* out) PRODUCT_RETURN;
};
--- a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.inline.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.inline.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -123,7 +123,6 @@
// to go back by.
size_t n_cards_back = BlockOffsetArray::entry_to_cards_back(offset);
q -= (N_words * n_cards_back);
- assert(q >= gsp()->bottom(), "Went below bottom!");
index -= n_cards_back;
offset = _array->offset_array(index);
}
--- a/hotspot/src/share/vm/gc/g1/g1CodeBlobClosure.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1CodeBlobClosure.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -36,7 +36,7 @@
T oop_or_narrowoop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(oop_or_narrowoop)) {
oop o = oopDesc::decode_heap_oop_not_null(oop_or_narrowoop);
- HeapRegion* hr = _g1h->heap_region_containing_raw(o);
+ HeapRegion* hr = _g1h->heap_region_containing(o);
assert(!_g1h->obj_in_cs(o) || hr->rem_set()->strong_code_roots_list_contains(_nm), "if o still in collection set then evacuation failed and nm must already be in the remset");
hr->add_strong_code_root(_nm);
}
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -320,12 +320,8 @@
// The header of the new object will be placed at the bottom of
// the first region.
HeapWord* new_obj = first_hr->bottom();
- // This will be the new end of the first region in the series that
- // should also match the end of the last region in the series.
- HeapWord* new_end = new_obj + word_size_sum;
- // This will be the new top of the first region that will reflect
- // this allocation.
- HeapWord* new_top = new_obj + word_size;
+ // This will be the new top of the new object.
+ HeapWord* obj_top = new_obj + word_size;
// First, we need to zero the header of the space that we will be
// allocating. When we update top further down, some refinement
@@ -346,7 +342,7 @@
// will also update the BOT covering all the regions to reflect
// that there is a single object that starts at the bottom of the
// first region.
- first_hr->set_starts_humongous(new_top, new_end);
+ first_hr->set_starts_humongous(obj_top);
first_hr->set_allocation_context(context);
// Then, if there are any, we will set up the "continues
// humongous" regions.
@@ -356,9 +352,6 @@
hr->set_continues_humongous(first_hr);
hr->set_allocation_context(context);
}
- // If we have "continues humongous" regions (hr != NULL), then the
- // end of the last one should match new_end.
- assert(hr == NULL || hr->end() == new_end, "sanity");
// Up to this point no concurrent thread would have been able to
// do any scanning on any region in this series. All the top
@@ -371,58 +364,39 @@
// Now that the BOT and the object header have been initialized,
// we can update top of the "starts humongous" region.
- assert(first_hr->bottom() < new_top && new_top <= first_hr->end(),
- "new_top should be in this region");
- first_hr->set_top(new_top);
+ first_hr->set_top(MIN2(first_hr->end(), obj_top));
if (_hr_printer.is_active()) {
- HeapWord* bottom = first_hr->bottom();
- HeapWord* end = first_hr->orig_end();
- if ((first + 1) == last) {
- // the series has a single humongous region
- _hr_printer.alloc(G1HRPrinter::SingleHumongous, first_hr, new_top);
- } else {
- // the series has more than one humongous regions
- _hr_printer.alloc(G1HRPrinter::StartsHumongous, first_hr, end);
- }
+ _hr_printer.alloc(G1HRPrinter::StartsHumongous, first_hr, first_hr->top());
}
// Now, we will update the top fields of the "continues humongous"
- // regions. The reason we need to do this is that, otherwise,
- // these regions would look empty and this will confuse parts of
- // G1. For example, the code that looks for a consecutive number
- // of empty regions will consider them empty and try to
- // re-allocate them. We can extend is_empty() to also include
- // !is_continues_humongous(), but it is easier to just update the top
- // fields here. The way we set top for all regions (i.e., top ==
- // end for all regions but the last one, top == new_top for the
- // last one) is actually used when we will free up the humongous
- // region in free_humongous_region().
+ // regions.
hr = NULL;
for (uint i = first + 1; i < last; ++i) {
hr = region_at(i);
if ((i + 1) == last) {
// last continues humongous region
- assert(hr->bottom() < new_top && new_top <= hr->end(),
+ assert(hr->bottom() < obj_top && obj_top <= hr->end(),
"new_top should fall on this region");
- hr->set_top(new_top);
- _hr_printer.alloc(G1HRPrinter::ContinuesHumongous, hr, new_top);
+ hr->set_top(obj_top);
+ _hr_printer.alloc(G1HRPrinter::ContinuesHumongous, hr, obj_top);
} else {
// not last one
- assert(new_top > hr->end(), "new_top should be above this region");
+ assert(obj_top > hr->end(), "obj_top should be above this region");
hr->set_top(hr->end());
_hr_printer.alloc(G1HRPrinter::ContinuesHumongous, hr, hr->end());
}
}
- // If we have continues humongous regions (hr != NULL), then the
- // end of the last one should match new_end and its top should
- // match new_top.
- assert(hr == NULL ||
- (hr->end() == new_end && hr->top() == new_top), "sanity");
+ // If we have continues humongous regions (hr != NULL), its top should
+ // match obj_top.
+ assert(hr == NULL || (hr->top() == obj_top), "sanity");
check_bitmaps("Humongous Region Allocation", first_hr);
- assert(first_hr->used() == word_size * HeapWordSize, "invariant");
- increase_used(first_hr->used());
- _humongous_set.add(first_hr);
+ increase_used(word_size * HeapWordSize);
+
+ for (uint i = first; i < last; ++i) {
+ _humongous_set.add(region_at(i));
+ }
return new_obj;
}
@@ -1139,15 +1113,15 @@
bool doHeapRegion(HeapRegion* r) {
HeapRegionRemSet* hrrs = r->rem_set();
+ _g1h->reset_gc_time_stamps(r);
+
if (r->is_continues_humongous()) {
// We'll assert that the strong code root list and RSet is empty
assert(hrrs->strong_code_roots_list_length() == 0, "sanity");
assert(hrrs->occupied() == 0, "RSet should be empty");
- return false;
+ } else {
+ hrrs->clear();
}
-
- _g1h->reset_gc_time_stamps(r);
- hrrs->clear();
// You might think here that we could clear just the cards
// corresponding to the used region. But no: if we leave a dirty card
// in a region we might allocate into, then it would prevent that card
@@ -1205,12 +1179,7 @@
if (hr->is_free()) {
// We only generate output for non-empty regions.
} else if (hr->is_starts_humongous()) {
- if (hr->region_num() == 1) {
- // single humongous region
- _hr_printer->post_compaction(hr, G1HRPrinter::SingleHumongous);
- } else {
- _hr_printer->post_compaction(hr, G1HRPrinter::StartsHumongous);
- }
+ _hr_printer->post_compaction(hr, G1HRPrinter::StartsHumongous);
} else if (hr->is_continues_humongous()) {
_hr_printer->post_compaction(hr, G1HRPrinter::ContinuesHumongous);
} else if (hr->is_archive()) {
@@ -1807,16 +1776,10 @@
// Public methods.
-#ifdef _MSC_VER // the use of 'this' below gets a warning, make it go away
-#pragma warning( disable:4355 ) // 'this' : used in base member initializer list
-#endif // _MSC_VER
-
-
G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) :
CollectedHeap(),
_g1_policy(policy_),
_dirty_card_queue_set(false),
- _into_cset_dirty_card_queue_set(false),
_is_alive_closure_cm(this),
_is_alive_closure_stw(this),
_ref_processor_cm(NULL),
@@ -2081,16 +2044,6 @@
Shared_DirtyCardQ_lock,
&JavaThread::dirty_card_queue_set());
- // Initialize the card queue set used to hold cards containing
- // references into the collection set.
- _into_cset_dirty_card_queue_set.initialize(NULL, // Should never be called by the Java code
- DirtyCardQ_CBL_mon,
- DirtyCardQ_FL_lock,
- -1, // never trigger processing
- -1, // no limit on length
- Shared_DirtyCardQ_lock,
- &JavaThread::dirty_card_queue_set());
-
// Here we allocate the dummy HeapRegion that is required by the
// G1AllocRegion class.
HeapRegion* dummy_region = _hrm.get_dummy_region();
@@ -2222,17 +2175,7 @@
}
void G1CollectedHeap::reset_gc_time_stamps(HeapRegion* hr) {
- assert(!hr->is_continues_humongous(), "pre-condition");
hr->reset_gc_time_stamp();
- if (hr->is_starts_humongous()) {
- uint first_index = hr->hrm_index() + 1;
- uint last_index = hr->last_hc_index();
- for (uint i = first_index; i < last_index; i += 1) {
- HeapRegion* chr = region_at(i);
- assert(chr->is_continues_humongous(), "sanity");
- chr->reset_gc_time_stamp();
- }
- }
}
#ifndef PRODUCT
@@ -2300,9 +2243,7 @@
public:
SumUsedClosure() : _used(0) {}
bool doHeapRegion(HeapRegion* r) {
- if (!r->is_continues_humongous()) {
- _used += r->used();
- }
+ _used += r->used();
return false;
}
size_t result() { return _used; }
@@ -2523,9 +2464,9 @@
bool G1CollectedHeap::is_in(const void* p) const {
if (_hrm.reserved().contains(p)) {
// Given that we know that p is in the reserved space,
- // heap_region_containing_raw() should successfully
+ // heap_region_containing() should successfully
// return the containing region.
- HeapRegion* hr = heap_region_containing_raw(p);
+ HeapRegion* hr = heap_region_containing(p);
return hr->is_in(p);
} else {
return false;
@@ -3062,7 +3003,7 @@
r->verify(_vo, &failures);
if (failures) {
_failures = true;
- } else {
+ } else if (!r->is_starts_humongous()) {
VerifyObjsInRegionClosure not_dead_yet_cl(r, _vo);
r->object_iterate(¬_dead_yet_cl);
if (_vo != VerifyOption_G1UseNextMarking) {
@@ -3613,7 +3554,7 @@
// The remembered set might contain references to already freed
// regions. Filter out such entries to avoid failing card table
// verification.
- if (!g1h->heap_region_containing(bs->addr_for(card_ptr))->is_free()) {
+ if (g1h->is_in_closed_subset(bs->addr_for(card_ptr))) {
if (*card_ptr != CardTableModRefBS::dirty_card_val()) {
*card_ptr = CardTableModRefBS::dirty_card_val();
_dcq.enqueue(card_ptr);
@@ -3735,8 +3676,7 @@
gclog_or_tty->print(" (to-space exhausted)");
}
gclog_or_tty->print_cr(", %3.7f secs]", pause_time_sec);
- g1_policy()->phase_times()->note_gc_end();
- g1_policy()->phase_times()->print(pause_time_sec);
+ g1_policy()->print_phases(pause_time_sec);
g1_policy()->print_detailed_heap_transition();
} else {
if (evacuation_failed()) {
@@ -3827,7 +3767,7 @@
workers()->set_active_workers(active_workers);
double pause_start_sec = os::elapsedTime();
- g1_policy()->phase_times()->note_gc_start(active_workers, collector_state()->mark_in_progress());
+ g1_policy()->note_gc_start(active_workers);
log_gc_header();
TraceCollectorStats tcs(g1mm()->incremental_collection_counters());
@@ -5270,6 +5210,9 @@
record_obj_copy_mem_stats();
+ _survivor_evac_stats.adjust_desired_plab_sz();
+ _old_evac_stats.adjust_desired_plab_sz();
+
// Reset and re-enable the hot card cache.
// Note the counts for the cards in the regions in the
// collection set are reset when the collection set is freed.
@@ -5315,30 +5258,16 @@
}
void G1CollectedHeap::free_humongous_region(HeapRegion* hr,
- FreeRegionList* free_list,
- bool par) {
- assert(hr->is_starts_humongous(), "this is only for starts humongous regions");
+ FreeRegionList* free_list,
+ bool par) {
+ assert(hr->is_humongous(), "this is only for humongous regions");
assert(free_list != NULL, "pre-condition");
-
- size_t hr_capacity = hr->capacity();
- // We need to read this before we make the region non-humongous,
- // otherwise the information will be gone.
- uint last_index = hr->last_hc_index();
hr->clear_humongous();
free_region(hr, free_list, par);
-
- uint i = hr->hrm_index() + 1;
- while (i < last_index) {
- HeapRegion* curr_hr = region_at(i);
- assert(curr_hr->is_continues_humongous(), "invariant");
- curr_hr->clear_humongous();
- free_region(curr_hr, free_list, par);
- i += 1;
- }
}
void G1CollectedHeap::remove_from_old_sets(const HeapRegionSetCount& old_regions_removed,
- const HeapRegionSetCount& humongous_regions_removed) {
+ const HeapRegionSetCount& humongous_regions_removed) {
if (old_regions_removed.length() > 0 || humongous_regions_removed.length() > 0) {
MutexLockerEx x(OldSets_lock, Mutex::_no_safepoint_check_flag);
_old_set.bulk_remove(old_regions_removed);
@@ -5498,8 +5427,6 @@
bool failures() { return _failures; }
virtual bool doHeapRegion(HeapRegion* hr) {
- if (hr->is_continues_humongous()) return false;
-
bool result = _g1h->verify_bitmaps(_caller, hr);
if (!result) {
_failures = true;
@@ -5773,11 +5700,10 @@
!r->rem_set()->is_empty()) {
if (G1TraceEagerReclaimHumongousObjects) {
- gclog_or_tty->print_cr("Live humongous region %u size " SIZE_FORMAT " start " PTR_FORMAT " length %u with remset " SIZE_FORMAT " code roots " SIZE_FORMAT " is marked %d reclaim candidate %d type array %d",
+ gclog_or_tty->print_cr("Live humongous region %u object size " SIZE_FORMAT " start " PTR_FORMAT " with remset " SIZE_FORMAT " code roots " SIZE_FORMAT " is marked %d reclaim candidate %d type array %d",
region_idx,
(size_t)obj->size() * HeapWordSize,
p2i(r->bottom()),
- r->region_num(),
r->rem_set()->occupied(),
r->rem_set()->strong_code_roots_list_length(),
next_bitmap->isMarked(r->bottom()),
@@ -5794,11 +5720,10 @@
PTR_FORMAT " is not.", p2i(r->bottom()));
if (G1TraceEagerReclaimHumongousObjects) {
- gclog_or_tty->print_cr("Dead humongous region %u size " SIZE_FORMAT " start " PTR_FORMAT " length %u with remset " SIZE_FORMAT " code roots " SIZE_FORMAT " is marked %d reclaim candidate %d type array %d",
+ gclog_or_tty->print_cr("Dead humongous region %u object size " SIZE_FORMAT " start " PTR_FORMAT " with remset " SIZE_FORMAT " code roots " SIZE_FORMAT " is marked %d reclaim candidate %d type array %d",
region_idx,
(size_t)obj->size() * HeapWordSize,
p2i(r->bottom()),
- r->region_num(),
r->rem_set()->occupied(),
r->rem_set()->strong_code_roots_list_length(),
next_bitmap->isMarked(r->bottom()),
@@ -5810,10 +5735,14 @@
if (next_bitmap->isMarked(r->bottom())) {
next_bitmap->clear(r->bottom());
}
- _freed_bytes += r->used();
- r->set_containing_set(NULL);
- _humongous_regions_removed.increment(1u, r->capacity());
- g1h->free_humongous_region(r, _free_region_list, false);
+ do {
+ HeapRegion* next = g1h->next_region_in_humongous(r);
+ _freed_bytes += r->used();
+ r->set_containing_set(NULL);
+ _humongous_regions_removed.increment(1u, r->capacity());
+ g1h->free_humongous_region(r, _free_region_list, false);
+ r = next;
+ } while (r != NULL);
return false;
}
@@ -6048,10 +5977,6 @@
}
bool doHeapRegion(HeapRegion* r) {
- if (r->is_continues_humongous()) {
- return false;
- }
-
if (r->is_empty()) {
// Add free regions to the free list
r->set_free();
@@ -6239,14 +6164,10 @@
_old_count(), _humongous_count(), _free_count(){ }
bool doHeapRegion(HeapRegion* hr) {
- if (hr->is_continues_humongous()) {
- return false;
- }
-
if (hr->is_young()) {
// TODO
- } else if (hr->is_starts_humongous()) {
- assert(hr->containing_set() == _humongous_set, "Heap region %u is starts humongous but not in humongous set.", hr->hrm_index());
+ } else if (hr->is_humongous()) {
+ assert(hr->containing_set() == _humongous_set, "Heap region %u is humongous but not in humongous set.", hr->hrm_index());
_humongous_count.increment(1u, hr->capacity());
} else if (hr->is_empty()) {
assert(_hrm->is_free(hr), "Heap region %u is empty but not on the free list.", hr->hrm_index());
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -757,12 +757,6 @@
// The closure used to refine a single card.
RefineCardTableEntryClosure* _refine_cte_cl;
- // A DirtyCardQueueSet that is used to hold cards that contain
- // references into the current collection set. This is used to
- // update the remembered sets of the regions in the collection
- // set in the event of an evacuation failure.
- DirtyCardQueueSet _into_cset_dirty_card_queue_set;
-
// After a collection pause, make the regions in the CS into free
// regions.
void free_collection_set(HeapRegion* cs_head, EvacuationInfo& evacuation_info, const size_t* surviving_young_words);
@@ -952,13 +946,6 @@
// A set of cards where updates happened during the GC
DirtyCardQueueSet& dirty_card_queue_set() { return _dirty_card_queue_set; }
- // A DirtyCardQueueSet that is used to hold cards that contain
- // references into the current collection set. This is used to
- // update the remembered sets of the regions in the collection
- // set in the event of an evacuation failure.
- DirtyCardQueueSet& into_cset_dirty_card_queue_set()
- { return _into_cset_dirty_card_queue_set; }
-
// Create a G1CollectedHeap with the specified policy.
// Must call the initialize method afterwards.
// May not return if something goes wrong.
@@ -1178,7 +1165,6 @@
void prepend_to_freelist(FreeRegionList* list);
void decrement_summary_bytes(size_t bytes);
- // Returns "TRUE" iff "p" points into the committed areas of the heap.
virtual bool is_in(const void* p) const;
#ifdef ASSERT
// Returns whether p is in one of the available areas of the heap. Slow but
@@ -1243,6 +1229,10 @@
// Return the region with the given index. It assumes the index is valid.
inline HeapRegion* region_at(uint index) const;
+ // Return the next region (by index) that is part of the same
+ // humongous object that hr is part of.
+ inline HeapRegion* next_region_in_humongous(HeapRegion* hr) const;
+
// Calculate the region index of the given address. Given address must be
// within the heap.
inline uint addr_to_region(HeapWord* addr) const;
@@ -1280,11 +1270,6 @@
// Returns the HeapRegion that contains addr. addr must not be NULL.
template <class T>
- inline HeapRegion* heap_region_containing_raw(const T addr) const;
-
- // Returns the HeapRegion that contains addr. addr must not be NULL.
- // If addr is within a humongous continues region, it returns its humongous start region.
- template <class T>
inline HeapRegion* heap_region_containing(const T addr) const;
// A CollectedHeap is divided into a dense sequence of "blocks"; that is,
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -65,6 +65,10 @@
// Return the region with the given index. It assumes the index is valid.
inline HeapRegion* G1CollectedHeap::region_at(uint index) const { return _hrm.at(index); }
+inline HeapRegion* G1CollectedHeap::next_region_in_humongous(HeapRegion* hr) const {
+ return _hrm.next_region_in_humongous(hr);
+}
+
inline uint G1CollectedHeap::addr_to_region(HeapWord* addr) const {
assert(is_in_reserved(addr),
"Cannot calculate region index for address " PTR_FORMAT " that is outside of the heap [" PTR_FORMAT ", " PTR_FORMAT ")",
@@ -77,7 +81,7 @@
}
template <class T>
-inline HeapRegion* G1CollectedHeap::heap_region_containing_raw(const T addr) const {
+inline HeapRegion* G1CollectedHeap::heap_region_containing(const T addr) const {
assert(addr != NULL, "invariant");
assert(is_in_g1_reserved((const void*) addr),
"Address " PTR_FORMAT " is outside of the heap ranging from [" PTR_FORMAT " to " PTR_FORMAT ")",
@@ -85,15 +89,6 @@
return _hrm.addr_to_region((HeapWord*) addr);
}
-template <class T>
-inline HeapRegion* G1CollectedHeap::heap_region_containing(const T addr) const {
- HeapRegion* hr = heap_region_containing_raw(addr);
- if (hr->is_continues_humongous()) {
- return hr->humongous_start_region();
- }
- return hr;
-}
-
inline void G1CollectedHeap::reset_gc_time_stamp() {
_gc_time_stamp = 0;
OrderAccess::fence();
@@ -124,9 +119,9 @@
assert_heap_not_locked();
// Assign the containing region to containing_hr so that we don't
- // have to keep calling heap_region_containing_raw() in the
+ // have to keep calling heap_region_containing() in the
// asserts below.
- DEBUG_ONLY(HeapRegion* containing_hr = heap_region_containing_raw(start);)
+ DEBUG_ONLY(HeapRegion* containing_hr = heap_region_containing(start);)
assert(word_size > 0, "pre-condition");
assert(containing_hr->is_in(start), "it should contain start");
assert(containing_hr->is_young(), "it should be young");
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -437,6 +437,10 @@
start_incremental_cset_building();
}
+void G1CollectorPolicy::note_gc_start(uint num_active_workers) {
+ phase_times()->note_gc_start(num_active_workers);
+}
+
// Create the jstat counters for the policy.
void G1CollectorPolicy::initialize_gc_policy_counters() {
_gc_policy_counters = new GCPolicyCounters("GarbageFirst", 1, 3);
@@ -807,7 +811,7 @@
// transitions and make sure we start with young GCs after the Full GC.
collector_state()->set_gcs_are_young(true);
collector_state()->set_last_young_gc(false);
- collector_state()->set_initiate_conc_mark_if_possible(false);
+ collector_state()->set_initiate_conc_mark_if_possible(need_to_start_conc_mark("end of Full GC", 0));
collector_state()->set_during_initial_mark_pause(false);
collector_state()->set_in_marking_window(false);
collector_state()->set_in_marking_window_im(false);
@@ -888,7 +892,9 @@
}
void G1CollectorPolicy::record_concurrent_mark_cleanup_completed() {
- collector_state()->set_last_young_gc(true);
+ bool should_continue_with_reclaim = next_gc_should_be_mixed("request last young-only gc",
+ "skip last young-only gc");
+ collector_state()->set_last_young_gc(should_continue_with_reclaim);
collector_state()->set_in_marking_window(false);
}
@@ -903,8 +909,35 @@
return phase_times()->average_time_ms(phase);
}
+double G1CollectorPolicy::young_other_time_ms() const {
+ return phase_times()->young_cset_choice_time_ms() +
+ phase_times()->young_free_cset_time_ms();
+}
+
+double G1CollectorPolicy::non_young_other_time_ms() const {
+ return phase_times()->non_young_cset_choice_time_ms() +
+ phase_times()->non_young_free_cset_time_ms();
+
+}
+
+double G1CollectorPolicy::other_time_ms(double pause_time_ms) const {
+ return pause_time_ms -
+ average_time_ms(G1GCPhaseTimes::UpdateRS) -
+ average_time_ms(G1GCPhaseTimes::ScanRS) -
+ average_time_ms(G1GCPhaseTimes::ObjCopy) -
+ average_time_ms(G1GCPhaseTimes::Termination);
+}
+
+double G1CollectorPolicy::constant_other_time_ms(double pause_time_ms) const {
+ return other_time_ms(pause_time_ms) - young_other_time_ms() - non_young_other_time_ms();
+}
+
+bool G1CollectorPolicy::about_to_start_mixed_phase() const {
+ return _g1->concurrent_mark()->cmThread()->during_cycle() || collector_state()->last_young_gc();
+}
+
bool G1CollectorPolicy::need_to_start_conc_mark(const char* source, size_t alloc_word_size) {
- if (_g1->concurrent_mark()->cmThread()->during_cycle()) {
+ if (about_to_start_mixed_phase()) {
return false;
}
@@ -972,11 +1005,8 @@
last_pause_included_initial_mark = collector_state()->during_initial_mark_pause();
if (last_pause_included_initial_mark) {
record_concurrent_mark_init_end(0.0);
- } else if (need_to_start_conc_mark("end of GC")) {
- // Note: this might have already been set, if during the last
- // pause we decided to start a cycle but at the beginning of
- // this pause we decided to postpone it. That's OK.
- collector_state()->set_initiate_conc_mark_if_possible(true);
+ } else {
+ maybe_start_marking();
}
_mmu_tracker->add_pause(end_time_sec - pause_time_ms/1000.0, end_time_sec);
@@ -1010,19 +1040,6 @@
_recent_avg_pause_time_ratio = _recent_gc_times_ms->sum()/interval_ms;
if (recent_avg_pause_time_ratio() < 0.0 ||
(recent_avg_pause_time_ratio() - 1.0 > 0.0)) {
-#ifndef PRODUCT
- // Dump info to allow post-facto debugging
- gclog_or_tty->print_cr("recent_avg_pause_time_ratio() out of bounds");
- gclog_or_tty->print_cr("-------------------------------------------");
- gclog_or_tty->print_cr("Recent GC Times (ms):");
- _recent_gc_times_ms->dump();
- gclog_or_tty->print_cr("(End Time=%3.3f) Recent GC End Times (s):", end_time_sec);
- _recent_prev_end_times_for_all_gcs_sec->dump();
- gclog_or_tty->print_cr("GC = %3.3f, Interval = %3.3f, Ratio = %3.3f",
- _recent_gc_times_ms->sum(), interval_ms, recent_avg_pause_time_ratio());
- // In debug mode, terminate the JVM if the user wants to debug at this point.
- assert(!G1FailOnFPError, "Debugging data for CR 6898948 has been dumped above");
-#endif // !PRODUCT
// Clip ratio between 0.0 and 1.0, and continue. This will be fixed in
// CR 6902692 by redoing the manner in which the ratio is incrementally computed.
if (_recent_avg_pause_time_ratio < 0.0) {
@@ -1044,17 +1061,13 @@
if (collector_state()->last_young_gc()) {
// This is supposed to to be the "last young GC" before we start
// doing mixed GCs. Here we decide whether to start mixed GCs or not.
+ assert(!last_pause_included_initial_mark, "The last young GC is not allowed to be an initial mark GC");
- if (!last_pause_included_initial_mark) {
- if (next_gc_should_be_mixed("start mixed GCs",
- "do not start mixed GCs")) {
- collector_state()->set_gcs_are_young(false);
- }
- } else {
- ergo_verbose0(ErgoMixedGCs,
- "do not start mixed GCs",
- ergo_format_reason("concurrent cycle is about to start"));
+ if (next_gc_should_be_mixed("start mixed GCs",
+ "do not start mixed GCs")) {
+ collector_state()->set_gcs_are_young(false);
}
+
collector_state()->set_last_young_gc(false);
}
@@ -1065,6 +1078,8 @@
if (!next_gc_should_be_mixed("continue mixed GCs",
"do not continue mixed GCs")) {
collector_state()->set_gcs_are_young(true);
+
+ maybe_start_marking();
}
}
@@ -1132,37 +1147,17 @@
}
}
- double all_other_time_ms = pause_time_ms -
- (average_time_ms(G1GCPhaseTimes::UpdateRS) + average_time_ms(G1GCPhaseTimes::ScanRS) +
- average_time_ms(G1GCPhaseTimes::ObjCopy) + average_time_ms(G1GCPhaseTimes::Termination));
-
- double young_other_time_ms = 0.0;
if (young_cset_region_length() > 0) {
- young_other_time_ms =
- phase_times()->young_cset_choice_time_ms() +
- phase_times()->young_free_cset_time_ms();
- _young_other_cost_per_region_ms_seq->add(young_other_time_ms /
- (double) young_cset_region_length());
- }
- double non_young_other_time_ms = 0.0;
- if (old_cset_region_length() > 0) {
- non_young_other_time_ms =
- phase_times()->non_young_cset_choice_time_ms() +
- phase_times()->non_young_free_cset_time_ms();
-
- _non_young_other_cost_per_region_ms_seq->add(non_young_other_time_ms /
- (double) old_cset_region_length());
+ _young_other_cost_per_region_ms_seq->add(young_other_time_ms() /
+ young_cset_region_length());
}
- double constant_other_time_ms = all_other_time_ms -
- (young_other_time_ms + non_young_other_time_ms);
- _constant_other_time_ms_seq->add(constant_other_time_ms);
+ if (old_cset_region_length() > 0) {
+ _non_young_other_cost_per_region_ms_seq->add(non_young_other_time_ms() /
+ old_cset_region_length());
+ }
- double survival_ratio = 0.0;
- if (_collection_set_bytes_used_before > 0) {
- survival_ratio = (double) _bytes_copied_during_gc /
- (double) _collection_set_bytes_used_before;
- }
+ _constant_other_time_ms_seq->add(constant_other_time_ms(pause_time_ms));
_pending_cards_seq->add((double) _pending_cards);
_rs_lengths_seq->add((double) _max_rs_lengths);
@@ -1271,6 +1266,10 @@
gclog_or_tty->cr();
}
+void G1CollectorPolicy::print_phases(double pause_time_sec) {
+ phase_times()->print(pause_time_sec);
+}
+
void G1CollectorPolicy::adjust_concurrent_refinement(double update_rs_time,
double update_rs_processed_buffers,
double goal_ms) {
@@ -1588,8 +1587,10 @@
HeapRegion::GrainWords * _max_survivor_regions, counters());
}
-bool G1CollectorPolicy::force_initial_mark_if_outside_cycle(
- GCCause::Cause gc_cause) {
+bool G1CollectorPolicy::force_initial_mark_if_outside_cycle(GCCause::Cause gc_cause) {
+ // We actually check whether we are marking here and not if we are in a
+ // reclamation phase. This means that we will schedule a concurrent mark
+ // even while we are still in the process of reclaiming memory.
bool during_cycle = _g1->concurrent_mark()->cmThread()->during_cycle();
if (!during_cycle) {
ergo_verbose1(ErgoConcCycles,
@@ -1609,8 +1610,7 @@
}
}
-void
-G1CollectorPolicy::decide_on_conc_mark_initiation() {
+void G1CollectorPolicy::decide_on_conc_mark_initiation() {
// We are about to decide on whether this pause will be an
// initial-mark pause.
@@ -1625,21 +1625,11 @@
// gone over the initiating threshold and we should start a
// concurrent marking cycle. So we might initiate one.
- bool during_cycle = _g1->concurrent_mark()->cmThread()->during_cycle();
- if (!during_cycle) {
- // The concurrent marking thread is not "during a cycle", i.e.,
- // it has completed the last one. So we can go ahead and
- // initiate a new cycle.
+ if (!about_to_start_mixed_phase() && collector_state()->gcs_are_young()) {
+ // Initiate a new initial mark only if there is no marking or reclamation going
+ // on.
collector_state()->set_during_initial_mark_pause(true);
- // We do not allow mixed GCs during marking.
- if (!collector_state()->gcs_are_young()) {
- collector_state()->set_gcs_are_young(true);
- ergo_verbose0(ErgoMixedGCs,
- "end mixed GCs",
- ergo_format_reason("concurrent cycle is about to start"));
- }
-
// And we can now clear initiate_conc_mark_if_possible() as
// we've already acted on it.
collector_state()->set_initiate_conc_mark_if_possible(false);
@@ -1943,6 +1933,15 @@
return (double) reclaimable_bytes * 100.0 / (double) capacity_bytes;
}
+void G1CollectorPolicy::maybe_start_marking() {
+ if (need_to_start_conc_mark("end of GC")) {
+ // Note: this might have already been set, if during the last
+ // pause we decided to start a cycle but at the beginning of
+ // this pause we decided to postpone it. That's OK.
+ collector_state()->set_initiate_conc_mark_if_possible(true);
+ }
+}
+
bool G1CollectorPolicy::next_gc_should_be_mixed(const char* true_action_str,
const char* false_action_str) const {
CollectionSetChooser* cset_chooser = _collectionSetChooser;
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -380,6 +380,11 @@
protected:
virtual double average_time_ms(G1GCPhaseTimes::GCParPhases phase) const;
+ virtual double other_time_ms(double pause_time_ms) const;
+
+ double young_other_time_ms() const;
+ double non_young_other_time_ms() const;
+ double constant_other_time_ms(double pause_time_ms) const;
private:
// Statistics kept per GC stoppage, pause or full.
@@ -529,6 +534,8 @@
// as a percentage of the current heap capacity.
double reclaimable_bytes_perc(size_t reclaimable_bytes) const;
+ // Sets up marking if proper conditions are met.
+ void maybe_start_marking();
public:
G1CollectorPolicy();
@@ -549,6 +556,8 @@
void init();
+ virtual void note_gc_start(uint num_active_workers);
+
// Create jstat counters for the policy.
virtual void initialize_gc_policy_counters();
@@ -563,6 +572,8 @@
bool need_to_start_conc_mark(const char* source, size_t alloc_word_size = 0);
+ bool about_to_start_mixed_phase() const;
+
// Record the start and end of an evacuation pause.
void record_collection_pause_start(double start_time_sec);
void record_collection_pause_end(double pause_time_ms, size_t cards_scanned);
@@ -593,6 +604,8 @@
void print_heap_transition() const;
void print_detailed_heap_transition(bool full = false) const;
+ virtual void print_phases(double pause_time_sec);
+
void record_stop_world_start();
void record_concurrent_pause();
--- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -136,7 +136,7 @@
_gc_par_phases[RedirtyCards]->link_thread_work_items(_redirtied_cards);
}
-void G1GCPhaseTimes::note_gc_start(uint active_gc_threads, bool mark_in_progress) {
+void G1GCPhaseTimes::note_gc_start(uint active_gc_threads) {
assert(active_gc_threads > 0, "The number of threads must be > 0");
assert(active_gc_threads <= _max_gc_threads, "The number of active threads must be <= the max number of threads");
_active_gc_threads = active_gc_threads;
@@ -362,6 +362,8 @@
};
void G1GCPhaseTimes::print(double pause_time_sec) {
+ note_gc_end();
+
G1GCParPhasePrinter par_phase_printer(this);
if (_root_region_scan_wait_time_ms > 0.0) {
--- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -121,10 +121,11 @@
void print_stats(int level, const char* str, size_t value);
void print_stats(int level, const char* str, double value, uint workers);
+ void note_gc_end();
+
public:
G1GCPhaseTimes(uint max_gc_threads);
- void note_gc_start(uint active_gc_threads, bool mark_in_progress);
- void note_gc_end();
+ void note_gc_start(uint active_gc_threads);
void print(double pause_time_sec);
// record the time a phase took in seconds
--- a/hotspot/src/share/vm/gc/g1/g1HRPrinter.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1HRPrinter.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -51,7 +51,6 @@
case Eden: return "Eden";
case Survivor: return "Survivor";
case Old: return "Old";
- case SingleHumongous: return "SingleH";
case StartsHumongous: return "StartsH";
case ContinuesHumongous: return "ContinuesH";
case Archive: return "Archive";
--- a/hotspot/src/share/vm/gc/g1/g1HRPrinter.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1HRPrinter.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -50,7 +50,6 @@
Eden,
Survivor,
Old,
- SingleHumongous,
StartsHumongous,
ContinuesHumongous,
Archive
--- a/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -279,8 +279,8 @@
} else {
assert(hr->is_empty(), "Should have been cleared in phase 2.");
}
- hr->reset_during_compaction();
}
+ hr->reset_during_compaction();
} else if (!hr->is_pinned()) {
hr->compact();
}
@@ -334,9 +334,6 @@
HeapWord* end = hr->end();
FreeRegionList dummy_free_list("Dummy Free List for G1MarkSweep");
- assert(hr->is_starts_humongous(),
- "Only the start of a humongous region should be freed.");
-
hr->set_containing_set(NULL);
_humongous_regions_removed.increment(1u, hr->capacity());
@@ -373,15 +370,12 @@
bool G1PrepareCompactClosure::doHeapRegion(HeapRegion* hr) {
if (hr->is_humongous()) {
- if (hr->is_starts_humongous()) {
- oop obj = oop(hr->bottom());
- if (obj->is_gc_marked()) {
- obj->forward_to(obj);
- } else {
- free_humongous_region(hr);
- }
- } else {
- assert(hr->is_continues_humongous(), "Invalid humongous.");
+ oop obj = oop(hr->humongous_start_region()->bottom());
+ if (hr->is_starts_humongous() && obj->is_gc_marked()) {
+ obj->forward_to(obj);
+ }
+ if (!obj->is_gc_marked()) {
+ free_humongous_region(hr);
}
} else if (!hr->is_pinned()) {
prepare_for_compaction(hr, hr->end());
--- a/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -117,11 +117,6 @@
template <class T>
inline void G1CMOopClosure::do_oop_nv(T* p) {
oop obj = oopDesc::load_decode_heap_oop(p);
- if (_cm->verbose_high()) {
- gclog_or_tty->print_cr("[%u] we're looking at location "
- "*" PTR_FORMAT " = " PTR_FORMAT,
- _task->worker_id(), p2i(p), p2i((void*) obj));
- }
_task->deal_with_reference(obj);
}
@@ -227,7 +222,7 @@
template <class T>
void G1ParCopyHelper::do_klass_barrier(T* p, oop new_obj) {
- if (_g1->heap_region_containing_raw(new_obj)->is_young()) {
+ if (_g1->heap_region_containing(new_obj)->is_young()) {
_scanned_klass->record_modified_oops();
}
}
--- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -216,7 +216,7 @@
oop const old,
markOop const old_mark) {
const size_t word_sz = old->size();
- HeapRegion* const from_region = _g1h->heap_region_containing_raw(old);
+ HeapRegion* const from_region = _g1h->heap_region_containing(old);
// +1 to make the -1 indexes valid...
const int young_index = from_region->young_index_in_cset()+1;
assert( (from_region->is_young() && young_index > 0) ||
@@ -294,9 +294,9 @@
if (G1StringDedup::is_enabled()) {
const bool is_from_young = state.is_young();
const bool is_to_young = dest_state.is_young();
- assert(is_from_young == _g1h->heap_region_containing_raw(old)->is_young(),
+ assert(is_from_young == _g1h->heap_region_containing(old)->is_young(),
"sanity");
- assert(is_to_young == _g1h->heap_region_containing_raw(obj)->is_young(),
+ assert(is_to_young == _g1h->heap_region_containing(obj)->is_young(),
"sanity");
G1StringDedup::enqueue_from_evacuation(is_from_young,
is_to_young,
@@ -314,7 +314,7 @@
oop* old_p = set_partial_array_mask(old);
push_on_queue(old_p);
} else {
- HeapRegion* const to_region = _g1h->heap_region_containing_raw(obj_ptr);
+ HeapRegion* const to_region = _g1h->heap_region_containing(obj_ptr);
_scanner.set_region(to_region);
obj->oop_iterate_backwards(&_scanner);
}
--- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.inline.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.inline.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -101,7 +101,7 @@
// so that the heap remains parsable in case of evacuation failure.
to_obj_array->set_length(end);
}
- _scanner.set_region(_g1h->heap_region_containing_raw(to_obj));
+ _scanner.set_region(_g1h->heap_region_containing(to_obj));
// Process indexes [start,end). It will also process the header
// along with the first chunk (i.e., the chunk with start == 0).
// Note that at this point the length field of to_obj_array is not
@@ -115,10 +115,7 @@
template <class T> inline void G1ParScanThreadState::deal_with_reference(T* ref_to_scan) {
if (!has_partial_array_mask(ref_to_scan)) {
- // Note: we can use "raw" versions of "region_containing" because
- // "obj_to_scan" is definitely in the heap, and is not in a
- // humongous region.
- HeapRegion* r = _g1h->heap_region_containing_raw(ref_to_scan);
+ HeapRegion* r = _g1h->heap_region_containing(ref_to_scan);
do_oop_evac(ref_to_scan, r);
} else {
do_oop_partial_array((oop*)ref_to_scan);
--- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -40,42 +40,13 @@
#include "utilities/intHisto.hpp"
#include "utilities/stack.inline.hpp"
-#define CARD_REPEAT_HISTO 0
-
-#if CARD_REPEAT_HISTO
-static size_t ct_freq_sz;
-static jbyte* ct_freq = NULL;
-
-void init_ct_freq_table(size_t heap_sz_bytes) {
- if (ct_freq == NULL) {
- ct_freq_sz = heap_sz_bytes/CardTableModRefBS::card_size;
- ct_freq = new jbyte[ct_freq_sz];
- for (size_t j = 0; j < ct_freq_sz; j++) ct_freq[j] = 0;
- }
-}
-
-void ct_freq_note_card(size_t index) {
- assert(0 <= index && index < ct_freq_sz, "Bounds error.");
- if (ct_freq[index] < 100) { ct_freq[index]++; }
-}
-
-static IntHistogram card_repeat_count(10, 10);
-
-void ct_freq_update_histo_and_reset() {
- for (size_t j = 0; j < ct_freq_sz; j++) {
- card_repeat_count.add_entry(ct_freq[j]);
- ct_freq[j] = 0;
- }
-
-}
-#endif
-
G1RemSet::G1RemSet(G1CollectedHeap* g1, CardTableModRefBS* ct_bs)
: _g1(g1), _conc_refine_cards(0),
_ct_bs(ct_bs), _g1p(_g1->g1_policy()),
_cg1r(g1->concurrent_g1_refine()),
_cset_rs_update_cl(NULL),
- _prev_period_summary()
+ _prev_period_summary(),
+ _into_cset_dirty_card_queue_set(false)
{
_cset_rs_update_cl = NEW_C_HEAP_ARRAY(G1ParPushHeapRSClosure*, n_workers(), mtGC);
for (uint i = 0; i < n_workers(); i++) {
@@ -84,6 +55,15 @@
if (G1SummarizeRSetStats) {
_prev_period_summary.initialize(this);
}
+ // Initialize the card queue set used to hold cards containing
+ // references into the collection set.
+ _into_cset_dirty_card_queue_set.initialize(NULL, // Should never be called by the Java code
+ DirtyCardQ_CBL_mon,
+ DirtyCardQ_FL_lock,
+ -1, // never trigger processing
+ -1, // no limit on length
+ Shared_DirtyCardQ_lock,
+ &JavaThread::dirty_card_queue_set());
}
G1RemSet::~G1RemSet() {
@@ -272,7 +252,7 @@
if (_g1rs->refine_card(card_ptr, worker_i, true)) {
// 'card_ptr' contains references that point into the collection
// set. We need to record the card in the DCQS
- // (G1CollectedHeap::into_cset_dirty_card_queue_set())
+ // (_into_cset_dirty_card_queue_set)
// that's used for that purpose.
//
// Enqueue the card
@@ -302,10 +282,6 @@
size_t G1RemSet::oops_into_collection_set_do(G1ParPushHeapRSClosure* oc,
CodeBlobClosure* heap_region_codeblobs,
uint worker_i) {
-#if CARD_REPEAT_HISTO
- ct_freq_update_histo_and_reset();
-#endif
-
// We cache the value of 'oc' closure into the appropriate slot in the
// _cset_rs_update_cl for this worker
assert(worker_i < n_workers(), "sanity");
@@ -320,7 +296,7 @@
// are wholly 'free' of live objects. In the event of an evacuation
// failure the cards/buffers in this queue set are passed to the
// DirtyCardQueueSet that is used to manage RSet updates
- DirtyCardQueue into_cset_dcq(&_g1->into_cset_dirty_card_queue_set());
+ DirtyCardQueue into_cset_dcq(&_into_cset_dirty_card_queue_set);
updateRS(&into_cset_dcq, worker_i);
size_t cards_scanned = scanRS(oc, heap_region_codeblobs, worker_i);
@@ -343,7 +319,7 @@
// Set all cards back to clean.
_g1->cleanUpCardTable();
- DirtyCardQueueSet& into_cset_dcqs = _g1->into_cset_dirty_card_queue_set();
+ DirtyCardQueueSet& into_cset_dcqs = _into_cset_dirty_card_queue_set;
int into_cset_n_buffers = into_cset_dcqs.completed_buffers_num();
if (_g1->evacuation_failed()) {
@@ -359,10 +335,10 @@
// Free any completed buffers in the DirtyCardQueueSet used to hold cards
// which contain references that point into the collection.
- _g1->into_cset_dirty_card_queue_set().clear();
- assert(_g1->into_cset_dirty_card_queue_set().completed_buffers_num() == 0,
+ _into_cset_dirty_card_queue_set.clear();
+ assert(_into_cset_dirty_card_queue_set.completed_buffers_num() == 0,
"all buffers should be freed");
- _g1->into_cset_dirty_card_queue_set().clear_n_completed_buffers();
+ _into_cset_dirty_card_queue_set.clear_n_completed_buffers();
}
class ScrubRSClosure: public HeapRegionClosure {
@@ -498,11 +474,6 @@
HeapWord* end = start + CardTableModRefBS::card_size_in_words;
MemRegion dirtyRegion(start, end);
-#if CARD_REPEAT_HISTO
- init_ct_freq_table(_g1->max_capacity());
- ct_freq_note_card(_ct_bs->index_for(start));
-#endif
-
G1ParPushHeapRSClosure* oops_in_heap_closure = NULL;
if (check_for_refs_into_cset) {
// ConcurrentG1RefineThreads have worker numbers larger than what
@@ -607,12 +578,6 @@
gclog_or_tty->print_cr("%s", header);
}
-#if CARD_REPEAT_HISTO
- gclog_or_tty->print_cr("\nG1 card_repeat count histogram: ");
- gclog_or_tty->print_cr(" # of repeats --> # of cards with that number.");
- card_repeat_count.print_on(gclog_or_tty);
-#endif
-
summary->print_on(gclog_or_tty);
}
@@ -631,9 +596,9 @@
bool use_hot_card_cache = hot_card_cache->use_cache();
hot_card_cache->set_use_cache(false);
- DirtyCardQueue into_cset_dcq(&_g1->into_cset_dirty_card_queue_set());
+ DirtyCardQueue into_cset_dcq(&_into_cset_dirty_card_queue_set);
updateRS(&into_cset_dcq, 0);
- _g1->into_cset_dirty_card_queue_set().clear();
+ _into_cset_dirty_card_queue_set.clear();
hot_card_cache->set_use_cache(use_hot_card_cache);
assert(JavaThread::dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed");
--- a/hotspot/src/share/vm/gc/g1/g1RemSet.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1RemSet.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -41,6 +41,13 @@
class G1RemSet: public CHeapObj<mtGC> {
private:
G1RemSetSummary _prev_period_summary;
+
+ // A DirtyCardQueueSet that is used to hold cards that contain
+ // references into the current collection set. This is used to
+ // update the remembered sets of the regions in the collection
+ // set in the event of an evacuation failure.
+ DirtyCardQueueSet _into_cset_dirty_card_queue_set;
+
protected:
G1CollectedHeap* _g1;
size_t _conc_refine_cards;
--- a/hotspot/src/share/vm/gc/g1/g1RemSet.inline.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1RemSet.inline.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -60,7 +60,7 @@
assert(_g1->is_in_reserved(obj), "must be in heap");
#endif // ASSERT
- assert(from == NULL || from->is_in_reserved(p), "p is not in from");
+ assert(from->is_in_reserved(p) || from->is_starts_humongous(), "p is not in from");
HeapRegion* to = _g1->heap_region_containing(obj);
if (from != to) {
--- a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
#include "gc/g1/heapRegion.hpp"
-#include "gc/g1/satbQueue.hpp"
+#include "gc/g1/satbMarkQueue.hpp"
#include "gc/shared/memset_with_concurrent_readers.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/atomic.inline.hpp"
@@ -189,21 +189,6 @@
}
void
-G1SATBCardTableLoggingModRefBS::write_ref_field_static(void* field,
- oop new_val) {
- uintptr_t field_uint = (uintptr_t)field;
- uintptr_t new_val_uint = cast_from_oop<uintptr_t>(new_val);
- uintptr_t comb = field_uint ^ new_val_uint;
- comb = comb >> HeapRegion::LogOfHRGrainBytes;
- if (comb == 0) return;
- if (new_val == NULL) return;
- // Otherwise, log it.
- G1SATBCardTableLoggingModRefBS* g1_bs =
- barrier_set_cast<G1SATBCardTableLoggingModRefBS>(G1CollectedHeap::heap()->barrier_set());
- g1_bs->write_ref_field_work(field, new_val, false);
-}
-
-void
G1SATBCardTableLoggingModRefBS::invalidate(MemRegion mr, bool whole_heap) {
volatile jbyte* byte = byte_for(mr.start());
jbyte* last_byte = byte_for(mr.last());
--- a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -56,21 +56,15 @@
virtual bool has_write_ref_pre_barrier() { return true; }
- // This notes that we don't need to access any BarrierSet data
- // structures, so this can be called from a static context.
- template <class T> static void write_ref_field_pre_static(T* field, oop newVal) {
+ // We export this to make it available in cases where the static
+ // type of the barrier set is known. Note that it is non-virtual.
+ template <class T> inline void inline_write_ref_field_pre(T* field, oop newVal) {
T heap_oop = oopDesc::load_heap_oop(field);
if (!oopDesc::is_null(heap_oop)) {
enqueue(oopDesc::decode_heap_oop(heap_oop));
}
}
- // We export this to make it available in cases where the static
- // type of the barrier set is known. Note that it is non-virtual.
- template <class T> inline void inline_write_ref_field_pre(T* field, oop newVal) {
- write_ref_field_pre_static(field, newVal);
- }
-
// These are the more general virtual versions.
virtual void write_ref_field_pre_work(oop* field, oop new_val) {
inline_write_ref_field_pre(field, new_val);
@@ -173,9 +167,6 @@
virtual void resize_covered_region(MemRegion new_region) { ShouldNotReachHere(); }
- // Can be called from static contexts.
- static void write_ref_field_static(void* field, oop new_val);
-
// NB: if you do a whole-heap invalidation, the "usual invariant" defined
// above no longer applies.
void invalidate(MemRegion mr, bool whole_heap = false);
--- a/hotspot/src/share/vm/gc/g1/g1StringDedup.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedup.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -52,7 +52,7 @@
bool G1StringDedup::is_candidate_from_mark(oop obj) {
if (java_lang_String::is_instance_inlined(obj)) {
- bool from_young = G1CollectedHeap::heap()->heap_region_containing_raw(obj)->is_young();
+ bool from_young = G1CollectedHeap::heap()->heap_region_containing(obj)->is_young();
if (from_young && obj->age() < StringDeduplicationAgeThreshold) {
// Candidate found. String is being evacuated from young to old but has not
// reached the deduplication age threshold, i.e. has not previously been a
--- a/hotspot/src/share/vm/gc/g1/g1_globals.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/g1_globals.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -48,9 +48,6 @@
develop(bool, G1TraceMarkStackOverflow, false, \
"If true, extra debugging code for CM restart for ovflw.") \
\
- develop(bool, G1TraceHeapRegionRememberedSet, false, \
- "Enables heap region remembered set debug logs") \
- \
diagnostic(bool, G1SummarizeConcMark, false, \
"Summarize concurrent mark info") \
\
@@ -187,12 +184,6 @@
range(0, max_jint/wordSize) \
constraint(G1RSetSparseRegionEntriesConstraintFunc,AfterErgo) \
\
- develop(bool, G1RecordHRRSOops, false, \
- "When true, record recent calls to rem set operations.") \
- \
- develop(bool, G1RecordHRRSEvents, false, \
- "When true, record recent calls to rem set operations.") \
- \
develop(intx, G1MaxVerifyFailures, -1, \
"The maximum number of verification failures to print. " \
"-1 means print all.") \
@@ -228,10 +219,6 @@
develop(bool, G1HRRSFlushLogBuffersOnVerify, false, \
"Forces flushing of log buffers before verification.") \
\
- develop(bool, G1FailOnFPError, false, \
- "When set, G1 will fail when it encounters an FP 'error', " \
- "so as to allow debugging") \
- \
product(size_t, G1HeapRegionSize, 0, \
"Size of the G1 regions.") \
range(0, 32*M) \
--- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -67,7 +67,7 @@
// not considered dead, either because it is marked (in the mark bitmap)
// or it was allocated after marking finished, then we add it. Otherwise
// we can safely ignore the object.
- if (!g1h->is_obj_dead(oop(cur), _hr)) {
+ if (!g1h->is_obj_dead(oop(cur))) {
oop_size = oop(cur)->oop_iterate_size(_rs_scan, mr);
} else {
oop_size = _hr->block_size(cur);
@@ -81,7 +81,7 @@
HeapWord* next_obj = cur + oop_size;
while (next_obj < top) {
// Keep filtering the remembered set.
- if (!g1h->is_obj_dead(cur_oop, _hr)) {
+ if (!g1h->is_obj_dead(cur_oop)) {
// Bottom lies entirely below top, so we can call the
// non-memRegion version of oop_iterate below.
cur_oop->oop_iterate(_rs_scan);
@@ -93,7 +93,7 @@
}
// Last object. Need to do dead-obj filtering here too.
- if (!g1h->is_obj_dead(oop(cur), _hr)) {
+ if (!g1h->is_obj_dead(oop(cur))) {
oop(cur)->oop_iterate(_rs_scan, mr);
}
}
@@ -162,8 +162,6 @@
void HeapRegion::hr_clear(bool par, bool clear_space, bool locked) {
assert(_humongous_start_region == NULL,
"we should have already filtered out humongous regions");
- assert(_end == orig_end(),
- "we should have already filtered out humongous regions");
assert(!in_collection_set(),
"Should not clear heap region %u in the collection set", hrm_index());
@@ -213,24 +211,18 @@
_gc_efficiency = (double) reclaimable_bytes() / region_elapsed_time_ms;
}
-void HeapRegion::set_starts_humongous(HeapWord* new_top, HeapWord* new_end) {
+void HeapRegion::set_starts_humongous(HeapWord* obj_top) {
assert(!is_humongous(), "sanity / pre-condition");
- assert(end() == orig_end(),
- "Should be normal before the humongous object allocation");
assert(top() == bottom(), "should be empty");
- assert(bottom() <= new_top && new_top <= new_end, "pre-condition");
_type.set_starts_humongous();
_humongous_start_region = this;
- set_end(new_end);
- _offsets.set_for_starts_humongous(new_top);
+ _offsets.set_for_starts_humongous(obj_top);
}
void HeapRegion::set_continues_humongous(HeapRegion* first_hr) {
assert(!is_humongous(), "sanity / pre-condition");
- assert(end() == orig_end(),
- "Should be normal before the humongous object allocation");
assert(top() == bottom(), "should be empty");
assert(first_hr->is_starts_humongous(), "pre-condition");
@@ -241,18 +233,6 @@
void HeapRegion::clear_humongous() {
assert(is_humongous(), "pre-condition");
- if (is_starts_humongous()) {
- assert(top() <= end(), "pre-condition");
- set_end(orig_end());
- if (top() > end()) {
- // at least one "continues humongous" region after it
- set_top(end());
- }
- } else {
- // continues humongous
- assert(end() == orig_end(), "sanity");
- }
-
assert(capacity() == HeapRegion::GrainBytes, "pre-condition");
_humongous_start_region = NULL;
}
@@ -290,11 +270,6 @@
hr_clear(false /*par*/, false /*clear_space*/);
set_top(bottom());
record_timestamp();
-
- assert(mr.end() == orig_end(),
- "Given region end address " PTR_FORMAT " should match exactly "
- "bottom plus one region size, i.e. " PTR_FORMAT,
- p2i(mr.end()), p2i(orig_end()));
}
CompactibleSpace* HeapRegion::next_compaction_space() const {
@@ -832,7 +807,14 @@
_offsets.verify();
}
- if (p != top()) {
+ if (is_region_humongous) {
+ oop obj = oop(this->humongous_start_region()->bottom());
+ if ((HeapWord*)obj > bottom() || (HeapWord*)obj + obj->size() < bottom()) {
+ gclog_or_tty->print_cr("this humongous region is not part of its' humongous object " PTR_FORMAT, p2i(obj));
+ }
+ }
+
+ if (!is_region_humongous && p != top()) {
gclog_or_tty->print_cr("end of last object " PTR_FORMAT " "
"does not match top " PTR_FORMAT, p2i(p), p2i(top()));
*failures = true;
@@ -840,7 +822,6 @@
}
HeapWord* the_end = end();
- assert(p == top(), "it should still hold");
// Do some extra BOT consistency checking for addresses in the
// range [top, end). BOT look-ups in this range should yield
// top. No point in doing that if top == end (there's nothing there).
@@ -931,6 +912,7 @@
}
void G1OffsetTableContigSpace::set_end(HeapWord* new_end) {
+ assert(new_end == _bottom + HeapRegion::GrainWords, "set_end should only ever be set to _bottom + HeapRegion::GrainWords");
Space::set_end(new_end);
_offsets.resize(new_end - bottom());
}
--- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -43,6 +43,15 @@
// The solution is to remove this method from the definition
// of a Space.
+// Each heap region is self contained. top() and end() can never
+// be set beyond the end of the region. For humongous objects,
+// the first region is a StartsHumongous region. If the humongous
+// object is larger than a heap region, the following regions will
+// be of type ContinuesHumongous. In this case the top() of the
+// StartHumongous region and all ContinuesHumongous regions except
+// the last will point to their own end. For the last ContinuesHumongous
+// region, top() will equal the object's top.
+
class G1CollectedHeap;
class HeapRegionRemSet;
class HeapRegionRemSetIterator;
@@ -389,8 +398,6 @@
size_t garbage_bytes() {
size_t used_at_mark_start_bytes =
(prev_top_at_mark_start() - bottom()) * HeapWordSize;
- assert(used_at_mark_start_bytes >= marked_bytes(),
- "Can't mark more than we have.");
return used_at_mark_start_bytes - marked_bytes();
}
@@ -409,7 +416,6 @@
void add_to_marked_bytes(size_t incr_bytes) {
_next_marked_bytes = _next_marked_bytes + incr_bytes;
- assert(_next_marked_bytes <= used(), "invariant" );
}
void zero_marked_bytes() {
@@ -445,57 +451,13 @@
return _humongous_start_region;
}
- // Return the number of distinct regions that are covered by this region:
- // 1 if the region is not humongous, >= 1 if the region is humongous.
- uint region_num() const {
- if (!is_humongous()) {
- return 1U;
- } else {
- assert(is_starts_humongous(), "doesn't make sense on HC regions");
- assert(capacity() % HeapRegion::GrainBytes == 0, "sanity");
- return (uint) (capacity() >> HeapRegion::LogOfHRGrainBytes);
- }
- }
-
- // Return the index + 1 of the last HC regions that's associated
- // with this HS region.
- uint last_hc_index() const {
- assert(is_starts_humongous(), "don't call this otherwise");
- return hrm_index() + region_num();
- }
-
- // Same as Space::is_in_reserved, but will use the original size of the region.
- // The original size is different only for start humongous regions. They get
- // their _end set up to be the end of the last continues region of the
- // corresponding humongous object.
- bool is_in_reserved_raw(const void* p) const {
- return _bottom <= p && p < orig_end();
- }
-
// Makes the current region be a "starts humongous" region, i.e.,
// the first region in a series of one or more contiguous regions
- // that will contain a single "humongous" object. The two parameters
- // are as follows:
- //
- // new_top : The new value of the top field of this region which
- // points to the end of the humongous object that's being
- // allocated. If there is more than one region in the series, top
- // will lie beyond this region's original end field and on the last
- // region in the series.
+ // that will contain a single "humongous" object.
//
- // new_end : The new value of the end field of this region which
- // points to the end of the last region in the series. If there is
- // one region in the series (namely: this one) end will be the same
- // as the original end of this region.
- //
- // Updating top and end as described above makes this region look as
- // if it spans the entire space taken up by all the regions in the
- // series and an single allocation moved its top to new_top. This
- // ensures that the space (capacity / allocated) taken up by all
- // humongous regions can be calculated by just looking at the
- // "starts humongous" regions and by ignoring the "continues
- // humongous" regions.
- void set_starts_humongous(HeapWord* new_top, HeapWord* new_end);
+ // obj_top : points to the end of the humongous object that's being
+ // allocated.
+ void set_starts_humongous(HeapWord* obj_top);
// Makes the current region be a "continues humongous'
// region. first_hr is the "start humongous" region of the series
@@ -566,9 +528,6 @@
void set_next_dirty_cards_region(HeapRegion* hr) { _next_dirty_cards_region = hr; }
bool is_on_dirty_cards_region_list() const { return get_next_dirty_cards_region() != NULL; }
- // For the start region of a humongous sequence, it's original end().
- HeapWord* orig_end() const { return _bottom + GrainWords; }
-
// Reset HR stuff to default values.
void hr_clear(bool par, bool clear_space, bool locked = false);
void par_clear();
@@ -614,8 +573,8 @@
bool is_marked() { return _prev_top_at_mark_start != bottom(); }
void reset_during_compaction() {
- assert(is_starts_humongous(),
- "should only be called for starts humongous regions");
+ assert(is_humongous(),
+ "should only be called for humongous regions");
zero_marked_bytes();
init_top_at_mark_start();
--- a/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -115,6 +115,11 @@
inline bool
HeapRegion::block_is_obj(const HeapWord* p) const {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
+
+ if (!this->is_in(p)) {
+ assert(is_continues_humongous(), "This case can only happen for humongous regions");
+ return (p == humongous_start_region()->bottom());
+ }
if (ClassUnloadingWithConcurrentMark) {
return !g1h->is_obj_dead(oop(p), this);
}
@@ -176,10 +181,6 @@
_prev_top_at_mark_start = _next_top_at_mark_start;
_prev_marked_bytes = _next_marked_bytes;
_next_marked_bytes = 0;
-
- assert(_prev_marked_bytes <=
- (size_t) pointer_delta(prev_top_at_mark_start(), bottom()) *
- HeapWordSize, "invariant");
}
inline void HeapRegion::note_start_of_copying(bool during_initial_mark) {
--- a/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -343,63 +343,18 @@
continue;
}
HeapRegion* r = _regions.get_by_index(index);
- // We'll ignore "continues humongous" regions (we'll process them
- // when we come across their corresponding "start humongous"
- // region) and regions already claimed.
+ // We'll ignore regions already claimed.
// However, if the iteration is specified as concurrent, the values for
// is_starts_humongous and is_continues_humongous can not be trusted,
// and we should just blindly iterate over regions regardless of their
// humongous status.
- if (hrclaimer->is_region_claimed(index) || (!concurrent && r->is_continues_humongous())) {
+ if (hrclaimer->is_region_claimed(index)) {
continue;
}
// OK, try to claim it
if (!hrclaimer->claim_region(index)) {
continue;
}
- // Success!
- // As mentioned above, special treatment of humongous regions can only be
- // done if we are iterating non-concurrently.
- if (!concurrent && r->is_starts_humongous()) {
- // If the region is "starts humongous" we'll iterate over its
- // "continues humongous" first; in fact we'll do them
- // first. The order is important. In one case, calling the
- // closure on the "starts humongous" region might de-allocate
- // and clear all its "continues humongous" regions and, as a
- // result, we might end up processing them twice. So, we'll do
- // them first (note: most closures will ignore them anyway) and
- // then we'll do the "starts humongous" region.
- for (uint ch_index = index + 1; ch_index < index + r->region_num(); ch_index++) {
- HeapRegion* chr = _regions.get_by_index(ch_index);
-
- assert(chr->is_continues_humongous(), "Must be humongous region");
- assert(chr->humongous_start_region() == r,
- "Must work on humongous continuation of the original start region "
- PTR_FORMAT ", but is " PTR_FORMAT, p2i(r), p2i(chr));
- assert(!hrclaimer->is_region_claimed(ch_index),
- "Must not have been claimed yet because claiming of humongous continuation first claims the start region");
-
- // Claim the region so no other worker tries to process the region. When a worker processes a
- // starts_humongous region it may also process the associated continues_humongous regions.
- // The continues_humongous regions can be changed to free regions. Unless this worker claims
- // all of these regions, other workers might try claim and process these newly free regions.
- bool claim_result = hrclaimer->claim_region(ch_index);
- guarantee(claim_result, "We should always be able to claim the continuesHumongous part of the humongous object");
-
- bool res2 = blk->doHeapRegion(chr);
- if (res2) {
- return;
- }
-
- // Right now, this holds (i.e., no closure that actually
- // does something with "continues humongous" regions
- // clears them). We might have to weaken it in the future,
- // but let's leave these two asserts here for extra safety.
- assert(chr->is_continues_humongous(), "should still be the case");
- assert(chr->humongous_start_region() == r, "sanity");
- }
- }
-
bool res = blk->doHeapRegion(r);
if (res) {
return;
@@ -508,11 +463,7 @@
// this method may be called, we have only completed allocation of the regions,
// but not put into a region set.
prev_committed = true;
- if (hr->is_starts_humongous()) {
- prev_end = hr->orig_end();
- } else {
- prev_end = hr->end();
- }
+ prev_end = hr->end();
}
for (uint i = _allocated_heapregions_length; i < max_length(); i++) {
guarantee(_regions.get_by_index(i) == NULL, "invariant i: %u", i);
--- a/hotspot/src/share/vm/gc/g1/heapRegionManager.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -150,6 +150,10 @@
// is valid.
inline HeapRegion* at(uint index) const;
+ // Return the next region (by index) that is part of the same
+ // humongous object that hr is part of.
+ inline HeapRegion* next_region_in_humongous(HeapRegion* hr) const;
+
// If addr is within the committed space return its corresponding
// HeapRegion, otherwise return NULL.
inline HeapRegion* addr_to_region(HeapWord* addr) const;
--- a/hotspot/src/share/vm/gc/g1/heapRegionManager.inline.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.inline.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -47,6 +47,18 @@
return hr;
}
+inline HeapRegion* HeapRegionManager::next_region_in_humongous(HeapRegion* hr) const {
+ uint index = hr->hrm_index();
+ assert(is_available(index), "pre-condition");
+ assert(hr->is_humongous(), "next_region_in_humongous should only be called for a humongous region.");
+ index++;
+ if (index < max_length() && is_available(index) && at(index)->is_continues_humongous()) {
+ return at(index);
+ } else {
+ return NULL;
+ }
+}
+
inline void HeapRegionManager::insert_into_free_list(HeapRegion* hr) {
_free_list.add_ordered(hr);
}
--- a/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -89,14 +89,6 @@
// Must make this robust in case "from" is not in "_hr", because of
// concurrency.
- if (G1TraceHeapRegionRememberedSet) {
- gclog_or_tty->print_cr(" PRT::Add_reference_work(" PTR_FORMAT "->" PTR_FORMAT ").",
- p2i(from),
- UseCompressedOops
- ? p2i(oopDesc::load_decode_heap_oop((narrowOop*)from))
- : p2i(oopDesc::load_decode_heap_oop((oop*)from)));
- }
-
HeapRegion* loc_hr = hr();
// If the test below fails, then this table was reused concurrently
// with this operation. This is OK, since the old table was coarsened,
@@ -105,7 +97,7 @@
// now reused for the corresponding start humongous region, we need to
// make sure that we detect this. Thus, we call is_in_reserved_raw()
// instead of just is_in_reserved() here.
- if (loc_hr->is_in_reserved_raw(from)) {
+ if (loc_hr->is_in_reserved(from)) {
size_t hw_offset = pointer_delta((HeapWord*)from, loc_hr->bottom());
CardIdx_t from_card = (CardIdx_t)
hw_offset >> (CardTableModRefBS::card_shift - LogHeapWordSize);
@@ -408,39 +400,19 @@
void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, uint tid) {
uint cur_hrm_ind = _hr->hrm_index();
- if (G1TraceHeapRegionRememberedSet) {
- gclog_or_tty->print_cr("ORT::add_reference_work(" PTR_FORMAT "->" PTR_FORMAT ").",
- p2i(from),
- UseCompressedOops
- ? p2i(oopDesc::load_decode_heap_oop((narrowOop*)from))
- : p2i(oopDesc::load_decode_heap_oop((oop*)from)));
- }
-
int from_card = (int)(uintptr_t(from) >> CardTableModRefBS::card_shift);
- if (G1TraceHeapRegionRememberedSet) {
- gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = %d)",
- p2i(_hr->bottom()), from_card,
- FromCardCache::at(tid, cur_hrm_ind));
- }
-
if (FromCardCache::contains_or_replace(tid, cur_hrm_ind, from_card)) {
- if (G1TraceHeapRegionRememberedSet) {
- gclog_or_tty->print_cr(" from-card cache hit.");
- }
assert(contains_reference(from), "We just added it!");
return;
}
// Note that this may be a continued H region.
- HeapRegion* from_hr = _g1h->heap_region_containing_raw(from);
+ HeapRegion* from_hr = _g1h->heap_region_containing(from);
RegionIdx_t from_hrm_ind = (RegionIdx_t) from_hr->hrm_index();
// If the region is already coarsened, return.
if (_coarse_map.at(from_hrm_ind)) {
- if (G1TraceHeapRegionRememberedSet) {
- gclog_or_tty->print_cr(" coarse map hit.");
- }
assert(contains_reference(from), "We just added it!");
return;
}
@@ -462,27 +434,8 @@
"Must be in range.");
if (G1HRRSUseSparseTable &&
_sparse_table.add_card(from_hrm_ind, card_index)) {
- if (G1RecordHRRSOops) {
- HeapRegionRemSet::record(_hr, from);
- if (G1TraceHeapRegionRememberedSet) {
- gclog_or_tty->print(" Added card " PTR_FORMAT " to region "
- "[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
- align_size_down(uintptr_t(from),
- CardTableModRefBS::card_size),
- p2i(_hr->bottom()), p2i(from));
- }
- }
- if (G1TraceHeapRegionRememberedSet) {
- gclog_or_tty->print_cr(" added card to sparse table.");
- }
assert(contains_reference_locked(from), "We just added it!");
return;
- } else {
- if (G1TraceHeapRegionRememberedSet) {
- gclog_or_tty->print_cr(" [tid %u] sparse table entry "
- "overflow(f: %d, t: %u)",
- tid, from_hrm_ind, cur_hrm_ind);
- }
}
if (_n_fine_entries == _max_fine_entries) {
@@ -531,17 +484,6 @@
assert(prt != NULL, "Inv");
prt->add_reference(from);
-
- if (G1RecordHRRSOops) {
- HeapRegionRemSet::record(_hr, from);
- if (G1TraceHeapRegionRememberedSet) {
- gclog_or_tty->print("Added card " PTR_FORMAT " to region "
- "[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
- align_size_down(uintptr_t(from),
- CardTableModRefBS::card_size),
- p2i(_hr->bottom()), p2i(from));
- }
- }
assert(contains_reference(from), "We just added it!");
}
@@ -606,13 +548,6 @@
if (!_coarse_map.at(max_hrm_index)) {
_coarse_map.at_put(max_hrm_index, true);
_n_coarse_entries++;
- if (G1TraceHeapRegionRememberedSet) {
- gclog_or_tty->print("Coarsened entry in region [" PTR_FORMAT "...] "
- "for region [" PTR_FORMAT "...] (" SIZE_FORMAT " coarse entries).\n",
- p2i(_hr->bottom()),
- p2i(max->hr()->bottom()),
- _n_coarse_entries);
- }
}
// Unsplice.
@@ -786,7 +721,7 @@
}
bool OtherRegionsTable::contains_reference_locked(OopOrNarrowOopStar from) const {
- HeapRegion* hr = _g1h->heap_region_containing_raw(from);
+ HeapRegion* hr = _g1h->heap_region_containing(from);
RegionIdx_t hr_ind = (RegionIdx_t) hr->hrm_index();
// Is this region in the coarse map?
if (_coarse_map.at(hr_ind)) return true;
@@ -1071,99 +1006,6 @@
return false;
}
-
-
-OopOrNarrowOopStar* HeapRegionRemSet::_recorded_oops = NULL;
-HeapWord** HeapRegionRemSet::_recorded_cards = NULL;
-HeapRegion** HeapRegionRemSet::_recorded_regions = NULL;
-int HeapRegionRemSet::_n_recorded = 0;
-
-HeapRegionRemSet::Event* HeapRegionRemSet::_recorded_events = NULL;
-int* HeapRegionRemSet::_recorded_event_index = NULL;
-int HeapRegionRemSet::_n_recorded_events = 0;
-
-void HeapRegionRemSet::record(HeapRegion* hr, OopOrNarrowOopStar f) {
- if (_recorded_oops == NULL) {
- assert(_n_recorded == 0
- && _recorded_cards == NULL
- && _recorded_regions == NULL,
- "Inv");
- _recorded_oops = NEW_C_HEAP_ARRAY(OopOrNarrowOopStar, MaxRecorded, mtGC);
- _recorded_cards = NEW_C_HEAP_ARRAY(HeapWord*, MaxRecorded, mtGC);
- _recorded_regions = NEW_C_HEAP_ARRAY(HeapRegion*, MaxRecorded, mtGC);
- }
- if (_n_recorded == MaxRecorded) {
- gclog_or_tty->print_cr("Filled up 'recorded' (%d).", MaxRecorded);
- } else {
- _recorded_cards[_n_recorded] =
- (HeapWord*)align_size_down(uintptr_t(f),
- CardTableModRefBS::card_size);
- _recorded_oops[_n_recorded] = f;
- _recorded_regions[_n_recorded] = hr;
- _n_recorded++;
- }
-}
-
-void HeapRegionRemSet::record_event(Event evnt) {
- if (!G1RecordHRRSEvents) return;
-
- if (_recorded_events == NULL) {
- assert(_n_recorded_events == 0
- && _recorded_event_index == NULL,
- "Inv");
- _recorded_events = NEW_C_HEAP_ARRAY(Event, MaxRecordedEvents, mtGC);
- _recorded_event_index = NEW_C_HEAP_ARRAY(int, MaxRecordedEvents, mtGC);
- }
- if (_n_recorded_events == MaxRecordedEvents) {
- gclog_or_tty->print_cr("Filled up 'recorded_events' (%d).", MaxRecordedEvents);
- } else {
- _recorded_events[_n_recorded_events] = evnt;
- _recorded_event_index[_n_recorded_events] = _n_recorded;
- _n_recorded_events++;
- }
-}
-
-void HeapRegionRemSet::print_event(outputStream* str, Event evnt) {
- switch (evnt) {
- case Event_EvacStart:
- str->print("Evac Start");
- break;
- case Event_EvacEnd:
- str->print("Evac End");
- break;
- case Event_RSUpdateEnd:
- str->print("RS Update End");
- break;
- }
-}
-
-void HeapRegionRemSet::print_recorded() {
- int cur_evnt = 0;
- Event cur_evnt_kind = Event_illegal;
- int cur_evnt_ind = 0;
- if (_n_recorded_events > 0) {
- cur_evnt_kind = _recorded_events[cur_evnt];
- cur_evnt_ind = _recorded_event_index[cur_evnt];
- }
-
- for (int i = 0; i < _n_recorded; i++) {
- while (cur_evnt < _n_recorded_events && i == cur_evnt_ind) {
- gclog_or_tty->print("Event: ");
- print_event(gclog_or_tty, cur_evnt_kind);
- gclog_or_tty->cr();
- cur_evnt++;
- if (cur_evnt < MaxRecordedEvents) {
- cur_evnt_kind = _recorded_events[cur_evnt];
- cur_evnt_ind = _recorded_event_index[cur_evnt];
- }
- }
- gclog_or_tty->print("Added card " PTR_FORMAT " to region [" PTR_FORMAT "...]"
- " for ref " PTR_FORMAT ".\n",
- p2i(_recorded_cards[i]), p2i(_recorded_regions[i]->bottom()),
- p2i(_recorded_oops[i]));
- }
-}
-
void HeapRegionRemSet::reset_for_cleanup_tasks() {
SparsePRT::reset_for_cleanup_tasks();
}
--- a/hotspot/src/share/vm/gc/g1/heapRegionRemSet.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/heapRegionRemSet.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -220,11 +220,6 @@
friend class VMStructs;
friend class HeapRegionRemSetIterator;
-public:
- enum Event {
- Event_EvacStart, Event_EvacEnd, Event_RSUpdateEnd, Event_illegal
- };
-
private:
G1BlockOffsetSharedArray* _bosa;
@@ -240,21 +235,6 @@
volatile ParIterState _iter_state;
volatile size_t _iter_claimed;
- // Unused unless G1RecordHRRSOops is true.
-
- static const int MaxRecorded = 1000000;
- static OopOrNarrowOopStar* _recorded_oops;
- static HeapWord** _recorded_cards;
- static HeapRegion** _recorded_regions;
- static int _n_recorded;
-
- static const int MaxRecordedEvents = 1000;
- static Event* _recorded_events;
- static int* _recorded_event_index;
- static int _n_recorded_events;
-
- static void print_event(outputStream* str, Event evnt);
-
public:
HeapRegionRemSet(G1BlockOffsetSharedArray* bosa, HeapRegion* hr);
@@ -404,10 +384,6 @@
}
#endif
- static void record(HeapRegion* hr, OopOrNarrowOopStar f);
- static void print_recorded();
- static void record_event(Event evnt);
-
// These are wrappers for the similarly-named methods on
// SparsePRT. Look at sparsePRT.hpp for more details.
static void reset_for_cleanup_tasks();
--- a/hotspot/src/share/vm/gc/g1/heapRegionSet.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/heapRegionSet.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -29,12 +29,6 @@
uint FreeRegionList::_unrealistically_long_length = 0;
-void HeapRegionSetBase::fill_in_ext_msg(hrs_ext_msg* msg, const char* message) {
- msg->append("[%s] %s ln: %u cy: " SIZE_FORMAT,
- name(), message, length(), total_capacity_bytes());
- fill_in_ext_msg_extra(msg);
-}
-
#ifndef PRODUCT
void HeapRegionSetBase::verify_region(HeapRegion* hr) {
assert(hr->containing_set() == this, "Inconsistent containing set for %u", hr->hrm_index());
@@ -55,16 +49,15 @@
// verification might fail and send us on a wild goose chase.
check_mt_safety();
- guarantee(( is_empty() && length() == 0 && total_capacity_bytes() == 0) ||
- (!is_empty() && length() > 0 && total_capacity_bytes() > 0) ,
- "%s", hrs_ext_msg(this, "invariant").buffer());
+ guarantee_heap_region_set(( is_empty() && length() == 0 && total_capacity_bytes() == 0) ||
+ (!is_empty() && length() > 0 && total_capacity_bytes() > 0) ,
+ "invariant");
}
void HeapRegionSetBase::verify_start() {
// See comment in verify() about MT safety and verification.
check_mt_safety();
- assert(!_verify_in_progress,
- "%s", hrs_ext_msg(this, "verification should not be in progress").buffer());
+ assert_heap_region_set(!_verify_in_progress, "verification should not be in progress");
// Do the basic verification first before we do the checks over the regions.
HeapRegionSetBase::verify();
@@ -75,8 +68,7 @@
void HeapRegionSetBase::verify_end() {
// See comment in verify() about MT safety and verification.
check_mt_safety();
- assert(_verify_in_progress,
- "%s", hrs_ext_msg(this, "verification should be in progress").buffer());
+ assert_heap_region_set(_verify_in_progress, "verification should be in progress");
_verify_in_progress = false;
}
@@ -104,10 +96,6 @@
_unrealistically_long_length = len;
}
-void FreeRegionList::fill_in_ext_msg_extra(hrs_ext_msg* msg) {
- msg->append(" hd: " PTR_FORMAT " tl: " PTR_FORMAT, p2i(_head), p2i(_tail));
-}
-
void FreeRegionList::remove_all() {
check_mt_safety();
verify_optional();
@@ -151,7 +139,7 @@
#endif // ASSERT
if (is_empty()) {
- assert(length() == 0 && _tail == NULL, "%s", hrs_ext_msg(this, "invariant").buffer());
+ assert_free_region_list(length() == 0 && _tail == NULL, "invariant");
_head = from_list->_head;
_tail = from_list->_tail;
} else {
@@ -198,8 +186,8 @@
void FreeRegionList::remove_starting_at(HeapRegion* first, uint num_regions) {
check_mt_safety();
- assert(num_regions >= 1, "%s", hrs_ext_msg(this, "pre-condition").buffer());
- assert(!is_empty(), "%s", hrs_ext_msg(this, "pre-condition").buffer());
+ assert_free_region_list(num_regions >= 1, "pre-condition");
+ assert_free_region_list(!is_empty(), "pre-condition");
verify_optional();
DEBUG_ONLY(uint old_length = length();)
@@ -212,25 +200,25 @@
HeapRegion* prev = curr->prev();
assert(count < num_regions,
- "%s", hrs_err_msg("[%s] should not come across more regions "
- "pending for removal than num_regions: %u",
- name(), num_regions).buffer());
+ "[%s] should not come across more regions "
+ "pending for removal than num_regions: %u",
+ name(), num_regions);
if (prev == NULL) {
- assert(_head == curr, "%s", hrs_ext_msg(this, "invariant").buffer());
+ assert_free_region_list(_head == curr, "invariant");
_head = next;
} else {
- assert(_head != curr, "%s", hrs_ext_msg(this, "invariant").buffer());
+ assert_free_region_list(_head != curr, "invariant");
prev->set_next(next);
}
if (next == NULL) {
- assert(_tail == curr, "%s", hrs_ext_msg(this, "invariant").buffer());
+ assert_free_region_list(_tail == curr, "invariant");
_tail = prev;
} else {
- assert(_tail != curr, "%s", hrs_ext_msg(this, "invariant").buffer());
+ assert_free_region_list(_tail != curr, "invariant");
next->set_prev(prev);
}
- if (_last = curr) {
+ if (_last == curr) {
_last = NULL;
}
@@ -243,12 +231,12 @@
}
assert(count == num_regions,
- "%s", hrs_err_msg("[%s] count: %u should be == num_regions: %u",
- name(), count, num_regions).buffer());
+ "[%s] count: %u should be == num_regions: %u",
+ name(), count, num_regions);
assert(length() + num_regions == old_length,
- "%s", hrs_err_msg("[%s] new length should be consistent "
- "new length: %u old length: %u num_regions: %u",
- name(), length(), old_length, num_regions).buffer());
+ "[%s] new length should be consistent "
+ "new length: %u old length: %u num_regions: %u",
+ name(), length(), old_length, num_regions);
verify_optional();
}
@@ -305,8 +293,8 @@
count++;
guarantee(count < _unrealistically_long_length,
- "%s", hrs_err_msg("[%s] the calculated length: %u seems very long, is there maybe a cycle? curr: " PTR_FORMAT " prev0: " PTR_FORMAT " " "prev1: " PTR_FORMAT " length: %u",
- name(), count, p2i(curr), p2i(prev0), p2i(prev1), length()).buffer());
+ "[%s] the calculated length: %u seems very long, is there maybe a cycle? curr: " PTR_FORMAT " prev0: " PTR_FORMAT " " "prev1: " PTR_FORMAT " length: %u",
+ name(), count, p2i(curr), p2i(prev0), p2i(prev1), length());
if (curr->next() != NULL) {
guarantee(curr->next()->prev() == curr, "Next or prev pointers messed up");
--- a/hotspot/src/share/vm/gc/g1/heapRegionSet.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/heapRegionSet.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -27,9 +27,24 @@
#include "gc/g1/heapRegion.hpp"
-// Large buffer for some cases where the output might be larger than normal.
-#define HRS_ERR_MSG_BUFSZ 512
-typedef FormatBuffer<HRS_ERR_MSG_BUFSZ> hrs_err_msg;
+#define assert_heap_region_set(p, message) \
+ do { \
+ assert((p), "[%s] %s ln: %u cy: " SIZE_FORMAT, \
+ name(), message, length(), total_capacity_bytes()); \
+ } while (0)
+
+#define guarantee_heap_region_set(p, message) \
+ do { \
+ guarantee((p), "[%s] %s ln: %u cy: " SIZE_FORMAT, \
+ name(), message, length(), total_capacity_bytes()); \
+ } while (0)
+
+#define assert_free_region_list(p, message) \
+ do { \
+ assert((p), "[%s] %s ln: %u cy: " SIZE_FORMAT " hd: " PTR_FORMAT " tl: " PTR_FORMAT, \
+ name(), message, length(), total_capacity_bytes(), p2i(_head), p2i(_tail)); \
+ } while (0)
+
// Set verification will be forced either if someone defines
// HEAP_REGION_SET_FORCE_VERIFY to be 1, or in builds in which
@@ -38,8 +53,6 @@
#define HEAP_REGION_SET_FORCE_VERIFY defined(ASSERT)
#endif // HEAP_REGION_SET_FORCE_VERIFY
-class hrs_ext_msg;
-
class HRSMtSafeChecker : public CHeapObj<mtGC> {
public:
virtual void check() = 0;
@@ -112,8 +125,6 @@
}
}
- virtual void fill_in_ext_msg_extra(hrs_ext_msg* msg) { }
-
HeapRegionSetBase(const char* name, bool humongous, bool free, HRSMtSafeChecker* mt_safety_checker);
public:
@@ -135,11 +146,6 @@
// from the set and tags the region appropriately.
inline void remove(HeapRegion* hr);
- // fill_in_ext_msg() writes the the values of the set's attributes
- // in the custom err_msg (hrs_ext_msg). fill_in_ext_msg_extra()
- // allows subclasses to append further information.
- void fill_in_ext_msg(hrs_ext_msg* msg, const char* message);
-
virtual void verify();
void verify_start();
void verify_next_region(HeapRegion* hr);
@@ -156,24 +162,13 @@
virtual void print_on(outputStream* out, bool print_contents = false);
};
-// Customized err_msg for heap region sets. Apart from a
-// assert/guarantee-specific message it also prints out the values of
-// the fields of the associated set. This can be very helpful in
-// diagnosing failures.
-class hrs_ext_msg : public hrs_err_msg {
-public:
- hrs_ext_msg(HeapRegionSetBase* set, const char* message) : hrs_err_msg("%s", "") {
- set->fill_in_ext_msg(this, message);
- }
-};
-
-#define hrs_assert_sets_match(_set1_, _set2_) \
- do { \
- assert(((_set1_)->regions_humongous() == \
- (_set2_)->regions_humongous()) && \
- ((_set1_)->regions_free() == (_set2_)->regions_free()), \
- hrs_err_msg("the contents of set %s and set %s should match", \
- (_set1_)->name(), (_set2_)->name())); \
+#define hrs_assert_sets_match(_set1_, _set2_) \
+ do { \
+ assert(((_set1_)->regions_humongous() == (_set2_)->regions_humongous()) && \
+ ((_set1_)->regions_free() == (_set2_)->regions_free()), \
+ "the contents of set %s and set %s should match", \
+ (_set1_)->name(), \
+ (_set2_)->name()); \
} while (0)
// This class represents heap region sets whose members are not
@@ -215,8 +210,6 @@
inline HeapRegion* remove_from_tail_impl();
protected:
- virtual void fill_in_ext_msg_extra(hrs_ext_msg* msg);
-
// See the comment for HeapRegionSetBase::clear()
virtual void clear();
--- a/hotspot/src/share/vm/gc/g1/heapRegionSet.inline.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/heapRegionSet.inline.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -29,9 +29,9 @@
inline void HeapRegionSetBase::add(HeapRegion* hr) {
check_mt_safety();
- assert(hr->containing_set() == NULL, "%s", hrs_ext_msg(this, "should not already have a containing set %u").buffer());
- assert(hr->next() == NULL, "%s", hrs_ext_msg(this, "should not already be linked").buffer());
- assert(hr->prev() == NULL, "%s", hrs_ext_msg(this, "should not already be linked").buffer());
+ assert_heap_region_set(hr->containing_set() == NULL, "should not already have a containing set");
+ assert_heap_region_set(hr->next() == NULL, "should not already be linked");
+ assert_heap_region_set(hr->prev() == NULL, "should not already be linked");
_count.increment(1u, hr->capacity());
hr->set_containing_set(this);
@@ -41,18 +41,18 @@
inline void HeapRegionSetBase::remove(HeapRegion* hr) {
check_mt_safety();
verify_region(hr);
- assert(hr->next() == NULL, "%s", hrs_ext_msg(this, "should already be unlinked").buffer());
- assert(hr->prev() == NULL, "%s", hrs_ext_msg(this, "should already be unlinked").buffer());
+ assert_heap_region_set(hr->next() == NULL, "should already be unlinked");
+ assert_heap_region_set(hr->prev() == NULL, "should already be unlinked");
hr->set_containing_set(NULL);
- assert(_count.length() > 0, "%s", hrs_ext_msg(this, "pre-condition").buffer());
+ assert_heap_region_set(_count.length() > 0, "pre-condition");
_count.decrement(1u, hr->capacity());
}
inline void FreeRegionList::add_ordered(HeapRegion* hr) {
- assert((length() == 0 && _head == NULL && _tail == NULL && _last == NULL) ||
- (length() > 0 && _head != NULL && _tail != NULL),
- "%s", hrs_ext_msg(this, "invariant").buffer());
+ assert_free_region_list((length() == 0 && _head == NULL && _tail == NULL && _last == NULL) ||
+ (length() > 0 && _head != NULL && _tail != NULL),
+ "invariant");
// add() will verify the region and check mt safety.
add(hr);
@@ -128,8 +128,7 @@
if (is_empty()) {
return NULL;
}
- assert(length() > 0 && _head != NULL && _tail != NULL,
- "%s", hrs_ext_msg(this, "invariant").buffer());
+ assert_free_region_list(length() > 0 && _head != NULL && _tail != NULL, "invariant");
HeapRegion* hr;
--- a/hotspot/src/share/vm/gc/g1/ptrQueue.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/ptrQueue.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -30,24 +30,25 @@
#include "runtime/mutexLocker.hpp"
#include "runtime/thread.inline.hpp"
-PtrQueue::PtrQueue(PtrQueueSet* qset, bool perm, bool active) :
+PtrQueue::PtrQueue(PtrQueueSet* qset, bool permanent, bool active) :
_qset(qset), _buf(NULL), _index(0), _sz(0), _active(active),
- _perm(perm), _lock(NULL)
+ _permanent(permanent), _lock(NULL)
{}
PtrQueue::~PtrQueue() {
- assert(_perm || (_buf == NULL), "queue must be flushed before delete");
+ assert(_permanent || (_buf == NULL), "queue must be flushed before delete");
}
void PtrQueue::flush_impl() {
- if (!_perm && _buf != NULL) {
+ if (!_permanent && _buf != NULL) {
if (_index == _sz) {
// No work to do.
qset()->deallocate_buffer(_buf);
} else {
// We must NULL out the unused entries, then enqueue.
- for (size_t i = 0; i < _index; i += oopSize) {
- _buf[byte_index_to_index((int)i)] = NULL;
+ size_t limit = byte_index_to_index(_index);
+ for (size_t i = 0; i < limit; ++i) {
+ _buf[i] = NULL;
}
qset()->enqueue_complete_buffer(_buf);
}
@@ -66,8 +67,8 @@
}
assert(_index > 0, "postcondition");
- _index -= oopSize;
- _buf[byte_index_to_index((int)_index)] = ptr;
+ _index -= sizeof(void*);
+ _buf[byte_index_to_index(_index)] = ptr;
assert(_index <= _sz, "Invariant.");
}
@@ -100,6 +101,26 @@
_fl_owner = this;
}
+PtrQueueSet::~PtrQueueSet() {
+ // There are presently only a couple (derived) instances ever
+ // created, and they are permanent, so no harm currently done by
+ // doing nothing here.
+}
+
+void PtrQueueSet::initialize(Monitor* cbl_mon,
+ Mutex* fl_lock,
+ int process_completed_threshold,
+ int max_completed_queue,
+ PtrQueueSet *fl_owner) {
+ _max_completed_queue = max_completed_queue;
+ _process_completed_threshold = process_completed_threshold;
+ _completed_queue_padding = 0;
+ assert(cbl_mon != NULL && fl_lock != NULL, "Init order issue?");
+ _cbl_mon = cbl_mon;
+ _fl_lock = fl_lock;
+ _fl_owner = (fl_owner != NULL) ? fl_owner : this;
+}
+
void** PtrQueueSet::allocate_buffer() {
assert(_sz > 0, "Didn't set a buffer size.");
MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag);
@@ -233,7 +254,7 @@
if (_notify_when_complete)
_cbl_mon->notify();
}
- debug_only(assert_completed_buffer_list_len_correct_locked());
+ DEBUG_ONLY(assert_completed_buffer_list_len_correct_locked());
}
int PtrQueueSet::completed_buffers_list_length() {
@@ -258,7 +279,7 @@
void PtrQueueSet::set_buffer_size(size_t sz) {
assert(_sz == 0 && sz > 0, "Should be called only once.");
- _sz = sz * oopSize;
+ _sz = sz * sizeof(void*);
}
// Merge lists of buffers. Notify the processing threads.
--- a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -40,44 +40,49 @@
class PtrQueue VALUE_OBJ_CLASS_SPEC {
friend class VMStructs;
-protected:
+ // Noncopyable - not defined.
+ PtrQueue(const PtrQueue&);
+ PtrQueue& operator=(const PtrQueue&);
+
// The ptr queue set to which this queue belongs.
- PtrQueueSet* _qset;
+ PtrQueueSet* const _qset;
// Whether updates should be logged.
bool _active;
+ // If true, the queue is permanent, and doesn't need to deallocate
+ // its buffer in the destructor (since that obtains a lock which may not
+ // be legally locked by then.
+ const bool _permanent;
+
+protected:
// The buffer.
void** _buf;
- // The index at which an object was last enqueued. Starts at "_sz"
+ // The (byte) index at which an object was last enqueued. Starts at "_sz"
// (indicating an empty buffer) and goes towards zero.
size_t _index;
- // The size of the buffer.
+ // The (byte) size of the buffer.
size_t _sz;
- // If true, the queue is permanent, and doesn't need to deallocate
- // its buffer in the destructor (since that obtains a lock which may not
- // be legally locked by then.
- bool _perm;
-
// If there is a lock associated with this buffer, this is that lock.
Mutex* _lock;
PtrQueueSet* qset() { return _qset; }
- bool is_permanent() const { return _perm; }
+ bool is_permanent() const { return _permanent; }
// Process queue entries and release resources, if not permanent.
void flush_impl();
-public:
// Initialize this queue to contain a null buffer, and be part of the
// given PtrQueueSet.
- PtrQueue(PtrQueueSet* qset, bool perm = false, bool active = false);
+ PtrQueue(PtrQueueSet* qset, bool permanent = false, bool active = false);
// Requires queue flushed or permanent.
~PtrQueue();
+public:
+
// Associate a lock with a ptr queue.
void set_lock(Mutex* lock) { _lock = lock; }
@@ -129,13 +134,9 @@
bool is_active() { return _active; }
- static int byte_index_to_index(int ind) {
- assert((ind % oopSize) == 0, "Invariant.");
- return ind / oopSize;
- }
-
- static int index_to_byte_index(int byte_ind) {
- return byte_ind * oopSize;
+ static size_t byte_index_to_index(size_t ind) {
+ assert((ind % sizeof(void*)) == 0, "Invariant.");
+ return ind / sizeof(void*);
}
// To support compiler.
@@ -246,26 +247,21 @@
return false;
}
-public:
// Create an empty ptr queue set.
PtrQueueSet(bool notify_when_complete = false);
+ ~PtrQueueSet();
// Because of init-order concerns, we can't pass these as constructor
// arguments.
- void initialize(Monitor* cbl_mon, Mutex* fl_lock,
+ void initialize(Monitor* cbl_mon,
+ Mutex* fl_lock,
int process_completed_threshold,
int max_completed_queue,
- PtrQueueSet *fl_owner = NULL) {
- _max_completed_queue = max_completed_queue;
- _process_completed_threshold = process_completed_threshold;
- _completed_queue_padding = 0;
- assert(cbl_mon != NULL && fl_lock != NULL, "Init order issue?");
- _cbl_mon = cbl_mon;
- _fl_lock = fl_lock;
- _fl_owner = (fl_owner != NULL) ? fl_owner : this;
- }
+ PtrQueueSet *fl_owner = NULL);
- // Return an empty oop array of size _sz (required to be non-zero).
+public:
+
+ // Return an empty array of size _sz (required to be non-zero).
void** allocate_buffer();
// Return an empty buffer to the free list. The "buf" argument is
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/satbMarkQueue.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/satbMarkQueue.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "memory/allocation.inline.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/thread.hpp"
+#include "runtime/vmThread.hpp"
+
+SATBMarkQueue::SATBMarkQueue(SATBMarkQueueSet* qset, bool permanent) :
+ // SATB queues are only active during marking cycles. We create
+ // them with their active field set to false. If a thread is
+ // created during a cycle and its SATB queue needs to be activated
+ // before the thread starts running, we'll need to set its active
+ // field to true. This is done in JavaThread::initialize_queues().
+ PtrQueue(qset, permanent, false /* active */)
+{ }
+
+void SATBMarkQueue::flush() {
+ // Filter now to possibly save work later. If filtering empties the
+ // buffer then flush_impl can deallocate the buffer.
+ filter();
+ flush_impl();
+}
+
+// Return true if a SATB buffer entry refers to an object that
+// requires marking.
+//
+// The entry must point into the G1 heap. In particular, it must not
+// be a NULL pointer. NULL pointers are pre-filtered and never
+// inserted into a SATB buffer.
+//
+// An entry that is below the NTAMS pointer for the containing heap
+// region requires marking. Such an entry must point to a valid object.
+//
+// An entry that is at least the NTAMS pointer for the containing heap
+// region might be any of the following, none of which should be marked.
+//
+// * A reference to an object allocated since marking started.
+// According to SATB, such objects are implicitly kept live and do
+// not need to be dealt with via SATB buffer processing.
+//
+// * A reference to a young generation object. Young objects are
+// handled separately and are not marked by concurrent marking.
+//
+// * A stale reference to a young generation object. If a young
+// generation object reference is recorded and not filtered out
+// before being moved by a young collection, the reference becomes
+// stale.
+//
+// * A stale reference to an eagerly reclaimed humongous object. If a
+// humongous object is recorded and then reclaimed, the reference
+// becomes stale.
+//
+// The stale reference cases are implicitly handled by the NTAMS
+// comparison. Because of the possibility of stale references, buffer
+// processing must be somewhat circumspect and not assume entries
+// in an unfiltered buffer refer to valid objects.
+
+inline bool requires_marking(const void* entry, G1CollectedHeap* heap) {
+ // Includes rejection of NULL pointers.
+ assert(heap->is_in_reserved(entry),
+ "Non-heap pointer in SATB buffer: " PTR_FORMAT, p2i(entry));
+
+ HeapRegion* region = heap->heap_region_containing(entry);
+ assert(region != NULL, "No region for " PTR_FORMAT, p2i(entry));
+ if (entry >= region->next_top_at_mark_start()) {
+ return false;
+ }
+
+ assert(((oop)entry)->is_oop(true /* ignore mark word */),
+ "Invalid oop in SATB buffer: " PTR_FORMAT, p2i(entry));
+
+ return true;
+}
+
+// This method removes entries from a SATB buffer that will not be
+// useful to the concurrent marking threads. Entries are retained if
+// they require marking and are not already marked. Retained entries
+// are compacted toward the top of the buffer.
+
+void SATBMarkQueue::filter() {
+ G1CollectedHeap* g1h = G1CollectedHeap::heap();
+ void** buf = _buf;
+
+ if (buf == NULL) {
+ // nothing to do
+ return;
+ }
+
+ // Used for sanity checking at the end of the loop.
+ DEBUG_ONLY(size_t entries = 0; size_t retained = 0;)
+
+ assert(_index <= _sz, "invariant");
+ void** limit = &buf[byte_index_to_index(_index)];
+ void** src = &buf[byte_index_to_index(_sz)];
+ void** dst = src;
+
+ while (limit < src) {
+ DEBUG_ONLY(entries += 1;)
+ --src;
+ void* entry = *src;
+ // NULL the entry so that unused parts of the buffer contain NULLs
+ // at the end. If we are going to retain it we will copy it to its
+ // final place. If we have retained all entries we have visited so
+ // far, we'll just end up copying it to the same place.
+ *src = NULL;
+
+ if (requires_marking(entry, g1h) && !g1h->isMarkedNext((oop)entry)) {
+ --dst;
+ assert(*dst == NULL, "filtering destination should be clear");
+ *dst = entry;
+ DEBUG_ONLY(retained += 1;);
+ }
+ }
+ size_t new_index = pointer_delta(dst, buf, 1);
+
+#ifdef ASSERT
+ size_t entries_calc = (_sz - _index) / sizeof(void*);
+ assert(entries == entries_calc, "the number of entries we counted "
+ "should match the number of entries we calculated");
+ size_t retained_calc = (_sz - new_index) / sizeof(void*);
+ assert(retained == retained_calc, "the number of retained entries we counted "
+ "should match the number of retained entries we calculated");
+#endif // ASSERT
+
+ _index = new_index;
+}
+
+// This method will first apply the above filtering to the buffer. If
+// post-filtering a large enough chunk of the buffer has been cleared
+// we can re-use the buffer (instead of enqueueing it) and we can just
+// allow the mutator to carry on executing using the same buffer
+// instead of replacing it.
+
+bool SATBMarkQueue::should_enqueue_buffer() {
+ assert(_lock == NULL || _lock->owned_by_self(),
+ "we should have taken the lock before calling this");
+
+ // If G1SATBBufferEnqueueingThresholdPercent == 0 we could skip filtering.
+
+ // This method should only be called if there is a non-NULL buffer
+ // that is full.
+ assert(_index == 0, "pre-condition");
+ assert(_buf != NULL, "pre-condition");
+
+ filter();
+
+ size_t percent_used = ((_sz - _index) * 100) / _sz;
+ bool should_enqueue = percent_used > G1SATBBufferEnqueueingThresholdPercent;
+ return should_enqueue;
+}
+
+void SATBMarkQueue::apply_closure_and_empty(SATBBufferClosure* cl) {
+ assert(SafepointSynchronize::is_at_safepoint(),
+ "SATB queues must only be processed at safepoints");
+ if (_buf != NULL) {
+ assert(_index % sizeof(void*) == 0, "invariant");
+ assert(_sz % sizeof(void*) == 0, "invariant");
+ assert(_index <= _sz, "invariant");
+ cl->do_buffer(_buf + byte_index_to_index(_index),
+ byte_index_to_index(_sz - _index));
+ _index = _sz;
+ }
+}
+
+#ifndef PRODUCT
+// Helpful for debugging
+
+void SATBMarkQueue::print(const char* name) {
+ print(name, _buf, _index, _sz);
+}
+
+void SATBMarkQueue::print(const char* name,
+ void** buf, size_t index, size_t sz) {
+ gclog_or_tty->print_cr(" SATB BUFFER [%s] buf: " PTR_FORMAT " "
+ "index: " SIZE_FORMAT " sz: " SIZE_FORMAT,
+ name, p2i(buf), index, sz);
+}
+#endif // PRODUCT
+
+SATBMarkQueueSet::SATBMarkQueueSet() :
+ PtrQueueSet(),
+ _shared_satb_queue(this, true /* permanent */) { }
+
+void SATBMarkQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock,
+ int process_completed_threshold,
+ Mutex* lock) {
+ PtrQueueSet::initialize(cbl_mon, fl_lock, process_completed_threshold, -1);
+ _shared_satb_queue.set_lock(lock);
+}
+
+void SATBMarkQueueSet::handle_zero_index_for_thread(JavaThread* t) {
+ t->satb_mark_queue().handle_zero_index();
+}
+
+#ifdef ASSERT
+void SATBMarkQueueSet::dump_active_states(bool expected_active) {
+ gclog_or_tty->print_cr("Expected SATB active state: %s",
+ expected_active ? "ACTIVE" : "INACTIVE");
+ gclog_or_tty->print_cr("Actual SATB active states:");
+ gclog_or_tty->print_cr(" Queue set: %s", is_active() ? "ACTIVE" : "INACTIVE");
+ for (JavaThread* t = Threads::first(); t; t = t->next()) {
+ gclog_or_tty->print_cr(" Thread \"%s\" queue: %s", t->name(),
+ t->satb_mark_queue().is_active() ? "ACTIVE" : "INACTIVE");
+ }
+ gclog_or_tty->print_cr(" Shared queue: %s",
+ shared_satb_queue()->is_active() ? "ACTIVE" : "INACTIVE");
+}
+
+void SATBMarkQueueSet::verify_active_states(bool expected_active) {
+ // Verify queue set state
+ if (is_active() != expected_active) {
+ dump_active_states(expected_active);
+ guarantee(false, "SATB queue set has an unexpected active state");
+ }
+
+ // Verify thread queue states
+ for (JavaThread* t = Threads::first(); t; t = t->next()) {
+ if (t->satb_mark_queue().is_active() != expected_active) {
+ dump_active_states(expected_active);
+ guarantee(false, "Thread SATB queue has an unexpected active state");
+ }
+ }
+
+ // Verify shared queue state
+ if (shared_satb_queue()->is_active() != expected_active) {
+ dump_active_states(expected_active);
+ guarantee(false, "Shared SATB queue has an unexpected active state");
+ }
+}
+#endif // ASSERT
+
+void SATBMarkQueueSet::set_active_all_threads(bool active, bool expected_active) {
+ assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
+#ifdef ASSERT
+ verify_active_states(expected_active);
+#endif // ASSERT
+ _all_active = active;
+ for (JavaThread* t = Threads::first(); t; t = t->next()) {
+ t->satb_mark_queue().set_active(active);
+ }
+ shared_satb_queue()->set_active(active);
+}
+
+void SATBMarkQueueSet::filter_thread_buffers() {
+ for(JavaThread* t = Threads::first(); t; t = t->next()) {
+ t->satb_mark_queue().filter();
+ }
+ shared_satb_queue()->filter();
+}
+
+bool SATBMarkQueueSet::apply_closure_to_completed_buffer(SATBBufferClosure* cl) {
+ BufferNode* nd = NULL;
+ {
+ MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
+ if (_completed_buffers_head != NULL) {
+ nd = _completed_buffers_head;
+ _completed_buffers_head = nd->next();
+ if (_completed_buffers_head == NULL) _completed_buffers_tail = NULL;
+ _n_completed_buffers--;
+ if (_n_completed_buffers == 0) _process_completed = false;
+ }
+ }
+ if (nd != NULL) {
+ void **buf = BufferNode::make_buffer_from_node(nd);
+ // Skip over NULL entries at beginning (e.g. push end) of buffer.
+ // Filtering can result in non-full completed buffers; see
+ // should_enqueue_buffer.
+ assert(_sz % sizeof(void*) == 0, "invariant");
+ size_t limit = SATBMarkQueue::byte_index_to_index(_sz);
+ for (size_t i = 0; i < limit; ++i) {
+ if (buf[i] != NULL) {
+ // Found the end of the block of NULLs; process the remainder.
+ cl->do_buffer(buf + i, limit - i);
+ break;
+ }
+ }
+ deallocate_buffer(buf);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+#ifndef PRODUCT
+// Helpful for debugging
+
+#define SATB_PRINTER_BUFFER_SIZE 256
+
+void SATBMarkQueueSet::print_all(const char* msg) {
+ char buffer[SATB_PRINTER_BUFFER_SIZE];
+ assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
+
+ gclog_or_tty->cr();
+ gclog_or_tty->print_cr("SATB BUFFERS [%s]", msg);
+
+ BufferNode* nd = _completed_buffers_head;
+ int i = 0;
+ while (nd != NULL) {
+ void** buf = BufferNode::make_buffer_from_node(nd);
+ jio_snprintf(buffer, SATB_PRINTER_BUFFER_SIZE, "Enqueued: %d", i);
+ SATBMarkQueue::print(buffer, buf, 0, _sz);
+ nd = nd->next();
+ i += 1;
+ }
+
+ for (JavaThread* t = Threads::first(); t; t = t->next()) {
+ jio_snprintf(buffer, SATB_PRINTER_BUFFER_SIZE, "Thread: %s", t->name());
+ t->satb_mark_queue().print(buffer);
+ }
+
+ shared_satb_queue()->print("Shared");
+
+ gclog_or_tty->cr();
+}
+#endif // PRODUCT
+
+void SATBMarkQueueSet::abandon_partial_marking() {
+ BufferNode* buffers_to_delete = NULL;
+ {
+ MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
+ while (_completed_buffers_head != NULL) {
+ BufferNode* nd = _completed_buffers_head;
+ _completed_buffers_head = nd->next();
+ nd->set_next(buffers_to_delete);
+ buffers_to_delete = nd;
+ }
+ _completed_buffers_tail = NULL;
+ _n_completed_buffers = 0;
+ DEBUG_ONLY(assert_completed_buffer_list_len_correct_locked());
+ }
+ while (buffers_to_delete != NULL) {
+ BufferNode* nd = buffers_to_delete;
+ buffers_to_delete = nd->next();
+ deallocate_buffer(BufferNode::make_buffer_from_node(nd));
+ }
+ assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
+ // So we can safely manipulate these queues.
+ for (JavaThread* t = Threads::first(); t; t = t->next()) {
+ t->satb_mark_queue().reset();
+ }
+ shared_satb_queue()->reset();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/satbMarkQueue.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_G1_SATBMARKQUEUE_HPP
+#define SHARE_VM_GC_G1_SATBMARKQUEUE_HPP
+
+#include "gc/g1/ptrQueue.hpp"
+#include "memory/allocation.hpp"
+
+class JavaThread;
+class SATBMarkQueueSet;
+
+// Base class for processing the contents of a SATB buffer.
+class SATBBufferClosure : public StackObj {
+protected:
+ ~SATBBufferClosure() { }
+
+public:
+ // Process the SATB entries in the designated buffer range.
+ virtual void do_buffer(void** buffer, size_t size) = 0;
+};
+
+// A PtrQueue whose elements are (possibly stale) pointers to object heads.
+class SATBMarkQueue: public PtrQueue {
+ friend class SATBMarkQueueSet;
+
+private:
+ // Filter out unwanted entries from the buffer.
+ void filter();
+
+public:
+ SATBMarkQueue(SATBMarkQueueSet* qset, bool permanent = false);
+
+ // Process queue entries and free resources.
+ void flush();
+
+ // Apply cl to the active part of the buffer.
+ // Prerequisite: Must be at a safepoint.
+ void apply_closure_and_empty(SATBBufferClosure* cl);
+
+ // Overrides PtrQueue::should_enqueue_buffer(). See the method's
+ // definition for more information.
+ virtual bool should_enqueue_buffer();
+
+#ifndef PRODUCT
+ // Helpful for debugging
+ void print(const char* name);
+ static void print(const char* name, void** buf, size_t index, size_t sz);
+#endif // PRODUCT
+};
+
+class SATBMarkQueueSet: public PtrQueueSet {
+ SATBMarkQueue _shared_satb_queue;
+
+#ifdef ASSERT
+ void dump_active_states(bool expected_active);
+ void verify_active_states(bool expected_active);
+#endif // ASSERT
+
+public:
+ SATBMarkQueueSet();
+
+ void initialize(Monitor* cbl_mon, Mutex* fl_lock,
+ int process_completed_threshold,
+ Mutex* lock);
+
+ static void handle_zero_index_for_thread(JavaThread* t);
+
+ // Apply "set_active(active)" to all SATB queues in the set. It should be
+ // called only with the world stopped. The method will assert that the
+ // SATB queues of all threads it visits, as well as the SATB queue
+ // set itself, has an active value same as expected_active.
+ void set_active_all_threads(bool active, bool expected_active);
+
+ // Filter all the currently-active SATB buffers.
+ void filter_thread_buffers();
+
+ // If there exists some completed buffer, pop and process it, and
+ // return true. Otherwise return false. Processing a buffer
+ // consists of applying the closure to the buffer range starting
+ // with the first non-NULL entry to the end of the buffer; the
+ // leading entries may be NULL due to filtering.
+ bool apply_closure_to_completed_buffer(SATBBufferClosure* cl);
+
+#ifndef PRODUCT
+ // Helpful for debugging
+ void print_all(const char* msg);
+#endif // PRODUCT
+
+ SATBMarkQueue* shared_satb_queue() { return &_shared_satb_queue; }
+
+ // If a marking is being abandoned, reset any unprocessed log buffers.
+ void abandon_partial_marking();
+};
+
+#endif // SHARE_VM_GC_G1_SATBMARKQUEUE_HPP
--- a/hotspot/src/share/vm/gc/g1/satbQueue.cpp Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,375 +0,0 @@
-/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
-#include "gc/g1/satbQueue.hpp"
-#include "gc/shared/collectedHeap.hpp"
-#include "memory/allocation.inline.hpp"
-#include "oops/oop.inline.hpp"
-#include "runtime/mutexLocker.hpp"
-#include "runtime/safepoint.hpp"
-#include "runtime/thread.hpp"
-#include "runtime/vmThread.hpp"
-
-void ObjPtrQueue::flush() {
- // Filter now to possibly save work later. If filtering empties the
- // buffer then flush_impl can deallocate the buffer.
- filter();
- flush_impl();
-}
-
-// Return true if a SATB buffer entry refers to an object that
-// requires marking.
-//
-// The entry must point into the G1 heap. In particular, it must not
-// be a NULL pointer. NULL pointers are pre-filtered and never
-// inserted into a SATB buffer.
-//
-// An entry that is below the NTAMS pointer for the containing heap
-// region requires marking. Such an entry must point to a valid object.
-//
-// An entry that is at least the NTAMS pointer for the containing heap
-// region might be any of the following, none of which should be marked.
-//
-// * A reference to an object allocated since marking started.
-// According to SATB, such objects are implicitly kept live and do
-// not need to be dealt with via SATB buffer processing.
-//
-// * A reference to a young generation object. Young objects are
-// handled separately and are not marked by concurrent marking.
-//
-// * A stale reference to a young generation object. If a young
-// generation object reference is recorded and not filtered out
-// before being moved by a young collection, the reference becomes
-// stale.
-//
-// * A stale reference to an eagerly reclaimed humongous object. If a
-// humongous object is recorded and then reclaimed, the reference
-// becomes stale.
-//
-// The stale reference cases are implicitly handled by the NTAMS
-// comparison. Because of the possibility of stale references, buffer
-// processing must be somewhat circumspect and not assume entries
-// in an unfiltered buffer refer to valid objects.
-
-inline bool requires_marking(const void* entry, G1CollectedHeap* heap) {
- // Includes rejection of NULL pointers.
- assert(heap->is_in_reserved(entry),
- "Non-heap pointer in SATB buffer: " PTR_FORMAT, p2i(entry));
-
- HeapRegion* region = heap->heap_region_containing_raw(entry);
- assert(region != NULL, "No region for " PTR_FORMAT, p2i(entry));
- if (entry >= region->next_top_at_mark_start()) {
- return false;
- }
-
- assert(((oop)entry)->is_oop(true /* ignore mark word */),
- "Invalid oop in SATB buffer: " PTR_FORMAT, p2i(entry));
-
- return true;
-}
-
-// This method removes entries from a SATB buffer that will not be
-// useful to the concurrent marking threads. Entries are retained if
-// they require marking and are not already marked. Retained entries
-// are compacted toward the top of the buffer.
-
-void ObjPtrQueue::filter() {
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
- void** buf = _buf;
- size_t sz = _sz;
-
- if (buf == NULL) {
- // nothing to do
- return;
- }
-
- // Used for sanity checking at the end of the loop.
- debug_only(size_t entries = 0; size_t retained = 0;)
-
- size_t i = sz;
- size_t new_index = sz;
-
- while (i > _index) {
- assert(i > 0, "we should have at least one more entry to process");
- i -= oopSize;
- debug_only(entries += 1;)
- void** p = &buf[byte_index_to_index((int) i)];
- void* entry = *p;
- // NULL the entry so that unused parts of the buffer contain NULLs
- // at the end. If we are going to retain it we will copy it to its
- // final place. If we have retained all entries we have visited so
- // far, we'll just end up copying it to the same place.
- *p = NULL;
-
- if (requires_marking(entry, g1h) && !g1h->isMarkedNext((oop)entry)) {
- assert(new_index > 0, "we should not have already filled up the buffer");
- new_index -= oopSize;
- assert(new_index >= i,
- "new_index should never be below i, as we always compact 'up'");
- void** new_p = &buf[byte_index_to_index((int) new_index)];
- assert(new_p >= p, "the destination location should never be below "
- "the source as we always compact 'up'");
- assert(*new_p == NULL,
- "we should have already cleared the destination location");
- *new_p = entry;
- debug_only(retained += 1;)
- }
- }
-
-#ifdef ASSERT
- size_t entries_calc = (sz - _index) / oopSize;
- assert(entries == entries_calc, "the number of entries we counted "
- "should match the number of entries we calculated");
- size_t retained_calc = (sz - new_index) / oopSize;
- assert(retained == retained_calc, "the number of retained entries we counted "
- "should match the number of retained entries we calculated");
-#endif // ASSERT
-
- _index = new_index;
-}
-
-// This method will first apply the above filtering to the buffer. If
-// post-filtering a large enough chunk of the buffer has been cleared
-// we can re-use the buffer (instead of enqueueing it) and we can just
-// allow the mutator to carry on executing using the same buffer
-// instead of replacing it.
-
-bool ObjPtrQueue::should_enqueue_buffer() {
- assert(_lock == NULL || _lock->owned_by_self(),
- "we should have taken the lock before calling this");
-
- // If G1SATBBufferEnqueueingThresholdPercent == 0 we could skip filtering.
-
- // This method should only be called if there is a non-NULL buffer
- // that is full.
- assert(_index == 0, "pre-condition");
- assert(_buf != NULL, "pre-condition");
-
- filter();
-
- size_t sz = _sz;
- size_t all_entries = sz / oopSize;
- size_t retained_entries = (sz - _index) / oopSize;
- size_t perc = retained_entries * 100 / all_entries;
- bool should_enqueue = perc > (size_t) G1SATBBufferEnqueueingThresholdPercent;
- return should_enqueue;
-}
-
-void ObjPtrQueue::apply_closure_and_empty(SATBBufferClosure* cl) {
- assert(SafepointSynchronize::is_at_safepoint(),
- "SATB queues must only be processed at safepoints");
- if (_buf != NULL) {
- assert(_index % sizeof(void*) == 0, "invariant");
- assert(_sz % sizeof(void*) == 0, "invariant");
- assert(_index <= _sz, "invariant");
- cl->do_buffer(_buf + byte_index_to_index((int)_index),
- byte_index_to_index((int)(_sz - _index)));
- _index = _sz;
- }
-}
-
-#ifndef PRODUCT
-// Helpful for debugging
-
-void ObjPtrQueue::print(const char* name) {
- print(name, _buf, _index, _sz);
-}
-
-void ObjPtrQueue::print(const char* name,
- void** buf, size_t index, size_t sz) {
- gclog_or_tty->print_cr(" SATB BUFFER [%s] buf: " PTR_FORMAT " "
- "index: " SIZE_FORMAT " sz: " SIZE_FORMAT,
- name, p2i(buf), index, sz);
-}
-#endif // PRODUCT
-
-#ifdef _MSC_VER // the use of 'this' below gets a warning, make it go away
-#pragma warning( disable:4355 ) // 'this' : used in base member initializer list
-#endif // _MSC_VER
-
-SATBMarkQueueSet::SATBMarkQueueSet() :
- PtrQueueSet(),
- _shared_satb_queue(this, true /*perm*/) { }
-
-void SATBMarkQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock,
- int process_completed_threshold,
- Mutex* lock) {
- PtrQueueSet::initialize(cbl_mon, fl_lock, process_completed_threshold, -1);
- _shared_satb_queue.set_lock(lock);
-}
-
-void SATBMarkQueueSet::handle_zero_index_for_thread(JavaThread* t) {
- t->satb_mark_queue().handle_zero_index();
-}
-
-#ifdef ASSERT
-void SATBMarkQueueSet::dump_active_states(bool expected_active) {
- gclog_or_tty->print_cr("Expected SATB active state: %s",
- expected_active ? "ACTIVE" : "INACTIVE");
- gclog_or_tty->print_cr("Actual SATB active states:");
- gclog_or_tty->print_cr(" Queue set: %s", is_active() ? "ACTIVE" : "INACTIVE");
- for (JavaThread* t = Threads::first(); t; t = t->next()) {
- gclog_or_tty->print_cr(" Thread \"%s\" queue: %s", t->name(),
- t->satb_mark_queue().is_active() ? "ACTIVE" : "INACTIVE");
- }
- gclog_or_tty->print_cr(" Shared queue: %s",
- shared_satb_queue()->is_active() ? "ACTIVE" : "INACTIVE");
-}
-
-void SATBMarkQueueSet::verify_active_states(bool expected_active) {
- // Verify queue set state
- if (is_active() != expected_active) {
- dump_active_states(expected_active);
- guarantee(false, "SATB queue set has an unexpected active state");
- }
-
- // Verify thread queue states
- for (JavaThread* t = Threads::first(); t; t = t->next()) {
- if (t->satb_mark_queue().is_active() != expected_active) {
- dump_active_states(expected_active);
- guarantee(false, "Thread SATB queue has an unexpected active state");
- }
- }
-
- // Verify shared queue state
- if (shared_satb_queue()->is_active() != expected_active) {
- dump_active_states(expected_active);
- guarantee(false, "Shared SATB queue has an unexpected active state");
- }
-}
-#endif // ASSERT
-
-void SATBMarkQueueSet::set_active_all_threads(bool active, bool expected_active) {
- assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
-#ifdef ASSERT
- verify_active_states(expected_active);
-#endif // ASSERT
- _all_active = active;
- for (JavaThread* t = Threads::first(); t; t = t->next()) {
- t->satb_mark_queue().set_active(active);
- }
- shared_satb_queue()->set_active(active);
-}
-
-void SATBMarkQueueSet::filter_thread_buffers() {
- for(JavaThread* t = Threads::first(); t; t = t->next()) {
- t->satb_mark_queue().filter();
- }
- shared_satb_queue()->filter();
-}
-
-bool SATBMarkQueueSet::apply_closure_to_completed_buffer(SATBBufferClosure* cl) {
- BufferNode* nd = NULL;
- {
- MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
- if (_completed_buffers_head != NULL) {
- nd = _completed_buffers_head;
- _completed_buffers_head = nd->next();
- if (_completed_buffers_head == NULL) _completed_buffers_tail = NULL;
- _n_completed_buffers--;
- if (_n_completed_buffers == 0) _process_completed = false;
- }
- }
- if (nd != NULL) {
- void **buf = BufferNode::make_buffer_from_node(nd);
- // Skip over NULL entries at beginning (e.g. push end) of buffer.
- // Filtering can result in non-full completed buffers; see
- // should_enqueue_buffer.
- assert(_sz % sizeof(void*) == 0, "invariant");
- size_t limit = ObjPtrQueue::byte_index_to_index((int)_sz);
- for (size_t i = 0; i < limit; ++i) {
- if (buf[i] != NULL) {
- // Found the end of the block of NULLs; process the remainder.
- cl->do_buffer(buf + i, limit - i);
- break;
- }
- }
- deallocate_buffer(buf);
- return true;
- } else {
- return false;
- }
-}
-
-#ifndef PRODUCT
-// Helpful for debugging
-
-#define SATB_PRINTER_BUFFER_SIZE 256
-
-void SATBMarkQueueSet::print_all(const char* msg) {
- char buffer[SATB_PRINTER_BUFFER_SIZE];
- assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
-
- gclog_or_tty->cr();
- gclog_or_tty->print_cr("SATB BUFFERS [%s]", msg);
-
- BufferNode* nd = _completed_buffers_head;
- int i = 0;
- while (nd != NULL) {
- void** buf = BufferNode::make_buffer_from_node(nd);
- jio_snprintf(buffer, SATB_PRINTER_BUFFER_SIZE, "Enqueued: %d", i);
- ObjPtrQueue::print(buffer, buf, 0, _sz);
- nd = nd->next();
- i += 1;
- }
-
- for (JavaThread* t = Threads::first(); t; t = t->next()) {
- jio_snprintf(buffer, SATB_PRINTER_BUFFER_SIZE, "Thread: %s", t->name());
- t->satb_mark_queue().print(buffer);
- }
-
- shared_satb_queue()->print("Shared");
-
- gclog_or_tty->cr();
-}
-#endif // PRODUCT
-
-void SATBMarkQueueSet::abandon_partial_marking() {
- BufferNode* buffers_to_delete = NULL;
- {
- MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
- while (_completed_buffers_head != NULL) {
- BufferNode* nd = _completed_buffers_head;
- _completed_buffers_head = nd->next();
- nd->set_next(buffers_to_delete);
- buffers_to_delete = nd;
- }
- _completed_buffers_tail = NULL;
- _n_completed_buffers = 0;
- DEBUG_ONLY(assert_completed_buffer_list_len_correct_locked());
- }
- while (buffers_to_delete != NULL) {
- BufferNode* nd = buffers_to_delete;
- buffers_to_delete = nd->next();
- deallocate_buffer(BufferNode::make_buffer_from_node(nd));
- }
- assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
- // So we can safely manipulate these queues.
- for (JavaThread* t = Threads::first(); t; t = t->next()) {
- t->satb_mark_queue().reset();
- }
- shared_satb_queue()->reset();
-}
--- a/hotspot/src/share/vm/gc/g1/satbQueue.hpp Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef SHARE_VM_GC_G1_SATBQUEUE_HPP
-#define SHARE_VM_GC_G1_SATBQUEUE_HPP
-
-#include "gc/g1/ptrQueue.hpp"
-#include "memory/allocation.hpp"
-
-class JavaThread;
-class SATBMarkQueueSet;
-
-// Base class for processing the contents of a SATB buffer.
-class SATBBufferClosure : public StackObj {
-protected:
- ~SATBBufferClosure() { }
-
-public:
- // Process the SATB entries in the designated buffer range.
- virtual void do_buffer(void** buffer, size_t size) = 0;
-};
-
-// A ptrQueue whose elements are "oops", pointers to object heads.
-class ObjPtrQueue: public PtrQueue {
- friend class SATBMarkQueueSet;
-
-private:
- // Filter out unwanted entries from the buffer.
- void filter();
-
-public:
- ObjPtrQueue(PtrQueueSet* qset, bool perm = false) :
- // SATB queues are only active during marking cycles. We create
- // them with their active field set to false. If a thread is
- // created during a cycle and its SATB queue needs to be activated
- // before the thread starts running, we'll need to set its active
- // field to true. This is done in JavaThread::initialize_queues().
- PtrQueue(qset, perm, false /* active */) { }
-
- // Process queue entries and free resources.
- void flush();
-
- // Apply cl to the active part of the buffer.
- // Prerequisite: Must be at a safepoint.
- void apply_closure_and_empty(SATBBufferClosure* cl);
-
- // Overrides PtrQueue::should_enqueue_buffer(). See the method's
- // definition for more information.
- virtual bool should_enqueue_buffer();
-
-#ifndef PRODUCT
- // Helpful for debugging
- void print(const char* name);
- static void print(const char* name, void** buf, size_t index, size_t sz);
-#endif // PRODUCT
-};
-
-class SATBMarkQueueSet: public PtrQueueSet {
- ObjPtrQueue _shared_satb_queue;
-
-#ifdef ASSERT
- void dump_active_states(bool expected_active);
- void verify_active_states(bool expected_active);
-#endif // ASSERT
-
-public:
- SATBMarkQueueSet();
-
- void initialize(Monitor* cbl_mon, Mutex* fl_lock,
- int process_completed_threshold,
- Mutex* lock);
-
- static void handle_zero_index_for_thread(JavaThread* t);
-
- // Apply "set_active(active)" to all SATB queues in the set. It should be
- // called only with the world stopped. The method will assert that the
- // SATB queues of all threads it visits, as well as the SATB queue
- // set itself, has an active value same as expected_active.
- void set_active_all_threads(bool active, bool expected_active);
-
- // Filter all the currently-active SATB buffers.
- void filter_thread_buffers();
-
- // If there exists some completed buffer, pop and process it, and
- // return true. Otherwise return false. Processing a buffer
- // consists of applying the closure to the buffer range starting
- // with the first non-NULL entry to the end of the buffer; the
- // leading entries may be NULL due to filtering.
- bool apply_closure_to_completed_buffer(SATBBufferClosure* cl);
-
-#ifndef PRODUCT
- // Helpful for debugging
- void print_all(const char* msg);
-#endif // PRODUCT
-
- ObjPtrQueue* shared_satb_queue() { return &_shared_satb_queue; }
-
- // If a marking is being abandoned, reset any unprocessed log buffers.
- void abandon_partial_marking();
-};
-
-#endif // SHARE_VM_GC_G1_SATBQUEUE_HPP
--- a/hotspot/src/share/vm/gc/g1/sparsePRT.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/g1/sparsePRT.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -32,8 +32,6 @@
#include "runtime/atomic.inline.hpp"
#include "runtime/mutexLocker.hpp"
-#define SPARSE_PRT_VERBOSE 0
-
void SparsePRTEntry::init(RegionIdx_t region_ind) {
_region_ind = region_ind;
_next_index = NullEntry;
@@ -121,11 +119,6 @@
"Postcondition of call above.");
SparsePRTEntry::AddCardResult res = e->add_card(card_index);
if (res == SparsePRTEntry::added) _occupied_cards++;
-#if SPARSE_PRT_VERBOSE
- gclog_or_tty->print_cr(" after add_card[%d]: valid-cards = %d.",
- pointer_delta(e, _entries, SparsePRTEntry::size()),
- e->num_valid_cards());
-#endif
assert(e->num_valid_cards() > 0, "Postcondition");
return res != SparsePRTEntry::overflow;
}
@@ -387,10 +380,6 @@
}
bool SparsePRT::add_card(RegionIdx_t region_id, CardIdx_t card_index) {
-#if SPARSE_PRT_VERBOSE
- gclog_or_tty->print_cr(" Adding card %d from region %d to region %u sparse.",
- card_index, region_id, _hr->hrm_index());
-#endif
if (_next->occupied_entries() * 2 > _next->capacity()) {
expand();
}
@@ -438,18 +427,9 @@
void SparsePRT::expand() {
RSHashTable* last = _next;
_next = new RSHashTable(last->capacity() * 2);
-
-#if SPARSE_PRT_VERBOSE
- gclog_or_tty->print_cr(" Expanded sparse table for %u to %d.",
- _hr->hrm_index(), _next->capacity());
-#endif
for (size_t i = 0; i < last->capacity(); i++) {
SparsePRTEntry* e = last->entry((int)i);
if (e->valid_entry()) {
-#if SPARSE_PRT_VERBOSE
- gclog_or_tty->print_cr(" During expansion, transferred entry for %d.",
- e->r_ind());
-#endif
_next->add_entry(e);
}
}
--- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -347,7 +347,7 @@
HeapWord* _partial_obj_addr;
region_sz_t _partial_obj_size;
region_sz_t volatile _dc_and_los;
- bool _blocks_filled;
+ bool volatile _blocks_filled;
#ifdef ASSERT
size_t _blocks_filled_count; // Number of block table fills.
@@ -498,7 +498,9 @@
inline bool
ParallelCompactData::RegionData::blocks_filled() const
{
- return _blocks_filled;
+ bool result = _blocks_filled;
+ OrderAccess::acquire();
+ return result;
}
#ifdef ASSERT
@@ -512,6 +514,7 @@
inline void
ParallelCompactData::RegionData::set_blocks_filled()
{
+ OrderAccess::release();
_blocks_filled = true;
// Debug builds count the number of times the table was filled.
DEBUG_ONLY(Atomic::inc_ptr(&_blocks_filled_count));
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -2190,7 +2190,7 @@
result->set_mark(markOopDesc::prototype());
}
result->set_klass_gap(0);
- result->set_klass(k_entry);
+ result->set_klass(ik);
// Must prevent reordering of stores for object initialization
// with stores that publish the new object.
OrderAccess::storestore();
--- a/hotspot/src/share/vm/libadt/dict.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/libadt/dict.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -126,37 +126,37 @@
void Dict::doubhash(void) {
uint oldsize = _size;
_size <<= 1; // Double in size
- _bin = (bucket*)_arena->Arealloc( _bin, sizeof(bucket)*oldsize, sizeof(bucket)*_size );
- memset( &_bin[oldsize], 0, oldsize*sizeof(bucket) );
+ _bin = (bucket*)_arena->Arealloc(_bin, sizeof(bucket) * oldsize, sizeof(bucket) * _size);
+ memset(&_bin[oldsize], 0, oldsize * sizeof(bucket));
// Rehash things to spread into new table
- for( uint i=0; i < oldsize; i++) { // For complete OLD table do
- bucket *b = &_bin[i]; // Handy shortcut for _bin[i]
- if( !b->_keyvals ) continue; // Skip empties fast
+ for (uint i = 0; i < oldsize; i++) { // For complete OLD table do
+ bucket *b = &_bin[i]; // Handy shortcut for _bin[i]
+ if (!b->_keyvals) continue; // Skip empties fast
- bucket *nb = &_bin[i+oldsize]; // New bucket shortcut
- uint j = b->_max; // Trim new bucket to nearest power of 2
- while( j > b->_cnt ) j >>= 1; // above old bucket _cnt
- if( !j ) j = 1; // Handle zero-sized buckets
- nb->_max = j<<1;
+ bucket *nb = &_bin[i+oldsize]; // New bucket shortcut
+ uint j = b->_max; // Trim new bucket to nearest power of 2
+ while (j > b->_cnt) { j >>= 1; } // above old bucket _cnt
+ if (!j) { j = 1; } // Handle zero-sized buckets
+ nb->_max = j << 1;
// Allocate worst case space for key-value pairs
- nb->_keyvals = (void**)_arena->Amalloc_4( sizeof(void *)*nb->_max*2 );
+ nb->_keyvals = (void**)_arena->Amalloc_4(sizeof(void *) * nb->_max * 2);
uint nbcnt = 0;
- for( j=0; j<b->_cnt; j++ ) { // Rehash all keys in this bucket
- void *key = b->_keyvals[j+j];
- if( (_hash( key ) & (_size-1)) != i ) { // Moving to hi bucket?
- nb->_keyvals[nbcnt+nbcnt] = key;
- nb->_keyvals[nbcnt+nbcnt+1] = b->_keyvals[j+j+1];
- nb->_cnt = nbcnt = nbcnt+1;
- b->_cnt--; // Remove key/value from lo bucket
- b->_keyvals[j+j ] = b->_keyvals[b->_cnt+b->_cnt ];
- b->_keyvals[j+j+1] = b->_keyvals[b->_cnt+b->_cnt+1];
- j--; // Hash compacted element also
+ for (j = 0; j < b->_cnt; ) { // Rehash all keys in this bucket
+ void *key = b->_keyvals[j + j];
+ if ((_hash(key) & (_size-1)) != i) { // Moving to hi bucket?
+ nb->_keyvals[nbcnt + nbcnt] = key;
+ nb->_keyvals[nbcnt + nbcnt + 1] = b->_keyvals[j + j + 1];
+ nb->_cnt = nbcnt = nbcnt + 1;
+ b->_cnt--; // Remove key/value from lo bucket
+ b->_keyvals[j + j] = b->_keyvals[b->_cnt + b->_cnt];
+ b->_keyvals[j + j + 1] = b->_keyvals[b->_cnt + b->_cnt + 1];
+ // Don't increment j, hash compacted element also.
+ } else {
+ j++; // Iterate.
}
} // End of for all key-value pairs in bucket
} // End of for all buckets
-
-
}
//------------------------------Dict-----------------------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/log.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+
+/////////////// Unit tests ///////////////
+
+#ifndef PRODUCT
+
+#include "logging/log.hpp"
+#include "logging/logConfiguration.hpp"
+#include "memory/resourceArea.hpp"
+
+void Test_log_length() {
+ remove("loglengthoutput.txt");
+
+ // Write long message to output file
+ MutexLocker ml(LogConfiguration_lock);
+ LogConfiguration::parse_log_arguments("loglengthoutput.txt", "logging=develop",
+ NULL, NULL, NULL);
+ ResourceMark rm;
+ outputStream* logstream = LogHandle(logging)::develop_stream();
+ logstream->print_cr("01:1234567890-"
+ "02:1234567890-"
+ "03:1234567890-"
+ "04:1234567890-"
+ "05:1234567890-"
+ "06:1234567890-"
+ "07:1234567890-"
+ "08:1234567890-"
+ "09:1234567890-"
+ "10:1234567890-"
+ "11:1234567890-"
+ "12:1234567890-"
+ "13:1234567890-"
+ "14:1234567890-"
+ "15:1234567890-"
+ "16:1234567890-"
+ "17:1234567890-"
+ "18:1234567890-"
+ "19:1234567890-"
+ "20:1234567890-"
+ "21:1234567890-"
+ "22:1234567890-"
+ "23:1234567890-"
+ "24:1234567890-"
+ "25:1234567890-"
+ "26:1234567890-"
+ "27:1234567890-"
+ "28:1234567890-"
+ "29:1234567890-"
+ "30:1234567890-"
+ "31:1234567890-"
+ "32:1234567890-"
+ "33:1234567890-"
+ "34:1234567890-"
+ "35:1234567890-"
+ "36:1234567890-"
+ "37:1234567890-");
+
+ // Look for end of message in output file
+ FILE* fp;
+ fp = fopen("loglengthoutput.txt", "r");
+ assert (fp, "File read error");
+ char output[600];
+ if (fgets(output, 600, fp) != NULL) {
+ assert(strstr(output, "37:1234567890-"), "logging print size error");
+ }
+ fclose(fp);
+ remove("loglengthoutput.txt");
+}
+#endif // PRODUCT
+
--- a/hotspot/src/share/vm/logging/log.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/logging/log.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -29,6 +29,8 @@
#include "logging/logTagSet.hpp"
#include "logging/logTag.hpp"
#include "memory/allocation.hpp"
+#include "memory/allocation.inline.hpp"
+#include "runtime/os.hpp"
#include "utilities/debug.hpp"
#include "utilities/ostream.hpp"
@@ -104,9 +106,20 @@
static void vwrite(const char* fmt, va_list args) {
char buf[LogBufferSize];
size_t prefix_len = LogPrefix<T0, T1, T2, T3, T4>::prefix(buf, sizeof(buf));
- int ret = vsnprintf(buf + prefix_len, sizeof(buf) - prefix_len, fmt, args);
- assert(ret >= 0 && (size_t)ret < sizeof(buf), "Log message too long");
- puts<Level>(buf);
+ // Check that string fits in buffer; resize buffer if necessary
+ int ret = os::log_vsnprintf(buf + prefix_len, sizeof(buf) - prefix_len, fmt, args);
+ assert(ret >= 0, "Log message buffer issue");
+ if ((size_t)ret > sizeof(buf)) {
+ size_t newbuf_len = prefix_len + ret + 1;
+ char* newbuf = NEW_C_HEAP_ARRAY(char, newbuf_len, mtLogging);
+ prefix_len = LogPrefix<T0, T1, T2, T3, T4>::prefix(newbuf, newbuf_len);
+ ret = os::log_vsnprintf(newbuf + prefix_len, newbuf_len - prefix_len, fmt, args);
+ assert(ret >= 0, "Log message buffer issue");
+ puts<Level>(newbuf);
+ FREE_C_HEAP_ARRAY(char, newbuf);
+ } else {
+ puts<Level>(buf);
+ }
}
template <LogLevelType Level>
--- a/hotspot/src/share/vm/logging/logTag.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/logging/logTag.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -31,7 +31,9 @@
// (The tags 'all', 'disable' and 'help' are special tags that can
// not be used in log calls, and should not be listed below.)
#define LOG_TAG_LIST \
- LOG_TAG(logging)
+ LOG_TAG(defaultmethods) \
+ LOG_TAG(logging) \
+ LOG_TAG(safepoint)
#define PREFIX_LOG_TAG(T) (LogTag::T)
--- a/hotspot/src/share/vm/precompiled/precompiled.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/precompiled/precompiled.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -304,7 +304,7 @@
# include "gc/g1/g1OopClosures.hpp"
# include "gc/g1/g1_globals.hpp"
# include "gc/g1/ptrQueue.hpp"
-# include "gc/g1/satbQueue.hpp"
+# include "gc/g1/satbMarkQueue.hpp"
# include "gc/parallel/gcAdaptivePolicyCounters.hpp"
# include "gc/parallel/objectStartArray.hpp"
# include "gc/parallel/parMarkBitMap.hpp"
--- a/hotspot/src/share/vm/prims/jni.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/prims/jni.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -3893,7 +3893,9 @@
void TestBitMap_test();
void TestAsUtf8();
void Test_linked_list();
+void TestResourcehash_test();
void TestChunkedList_test();
+void Test_log_length();
#if INCLUDE_ALL_GCS
void TestOldFreeSpaceCalculation_test();
void TestG1BiasedArray_test();
@@ -3930,10 +3932,12 @@
run_unit_test(TestKlass_test());
run_unit_test(TestBitMap_test());
run_unit_test(TestAsUtf8());
+ run_unit_test(TestResourcehash_test());
run_unit_test(ObjectMonitor::sanity_checks());
run_unit_test(Test_linked_list());
run_unit_test(TestChunkedList_test());
run_unit_test(JSONTest::test());
+ run_unit_test(Test_log_length());
run_unit_test(DirectivesParser::test());
#if INCLUDE_VM_STRUCTS
run_unit_test(VMStructs::test());
--- a/hotspot/src/share/vm/prims/jvmtiGen.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiGen.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,52 +22,60 @@
*
*/
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.transform.stream.StreamResult;
+import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.w3c.dom.Document;
import org.w3c.dom.DOMException;
-// For write operation
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamSource;
-import javax.xml.transform.stream.StreamResult;
-
-import java.io.*;
public class jvmtiGen
{
+ private static final int EXIT_FAILURE_ERROR = 1;
+ private static final int EXIT_FAILURE_BADARGUMENTS = 2;
+
+ private static boolean verbose = false;
+
/**
* Write out usage and exit.
*/
private static void showUsage() {
System.err.println("usage:");
System.err.println(" java jvmtiGen " +
+ "[-verbose] " +
"-IN <input XML file name> " +
"-XSL <XSL file> " +
"-OUT <output file name> " +
"[-PARAM <name> <expression> ...]");
- System.exit(0); // There is no returning from showUsage()
+ System.exit(EXIT_FAILURE_BADARGUMENTS); // There is no returning from showUsage()
}
- // Global value so it can be ref'd by the tree-adapter
- static Document document;
-
- public static void main (String argv [])
- {
- String inFileName=null;
- String xslFileName=null;
- String outFileName=null;
- java.util.Vector<String> params=new java.util.Vector<String>();
+ public static void main (String argv []) {
+ String inFileName = null;
+ String xslFileName = null;
+ String outFileName = null;
+ final List<String> params = new ArrayList<String>();
for (int ii = 0; ii < argv.length; ii++) {
- if (argv[ii].equals("-IN")) {
+ if (argv[ii].equals("-verbose")) {
+ verbose = true;
+ } else if (argv[ii].equals("-IN")) {
inFileName = argv[++ii];
} else if (argv[ii].equals("-XSL")) {
xslFileName = argv[++ii];
@@ -75,10 +83,10 @@
outFileName = argv[++ii];
} else if (argv[ii].equals("-PARAM")) {
if (ii + 2 < argv.length) {
- String name = argv[++ii];
- params.addElement(name);
- String expression = argv[++ii];
- params.addElement(expression);
+ final String name = argv[++ii];
+ params.add(name);
+ final String expression = argv[++ii];
+ params.add(expression);
} else {
showUsage();
}
@@ -86,109 +94,54 @@
showUsage();
}
}
- if (inFileName==null || xslFileName==null || outFileName==null){
+ if (inFileName == null || xslFileName == null || outFileName == null) {
showUsage();
}
- /*
- * Due to JAXP breakage in some intermediate Tiger builds, the
- * com.sun.org.apache..... parser may throw an exception:
- * com.sun.org.apache.xml.internal.utils.WrappedRuntimeException:
- * org.apache.xalan.serialize.SerializerToText
- *
- * To work around the problem, this program uses the
- * org.apache.xalan.... version if it is available. It is
- * available in J2SE 1.4.x and early builds of 1.5 (Tiger).
- * It was removed at the same time the thrown exception issue
- * above was fixed, so if the class is not found we can proceed
- * and use the default parser.
- */
- final String parserProperty =
- "javax.xml.transform.TransformerFactory";
- final String workaroundParser =
- "org.apache.xalan.processor.TransformerFactoryImpl";
-
- try {
- java.lang.Class cls = java.lang.Class.forName(workaroundParser);
- /*
- * If we get here, we found the class. Use it.
- */
- System.setProperty(parserProperty, workaroundParser);
- System.out.println("Info: jvmtiGen using " + parserProperty +
- " = " + workaroundParser);
- } catch (ClassNotFoundException cnfex) {
- /*
- * We didn't find workaroundParser. Ignore the
- * exception and proceed with default settings.
- */
- }
-
- DocumentBuilderFactory factory =
- DocumentBuilderFactory.newInstance();
+ final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(true);
factory.setXIncludeAware(true);
- try {
- File datafile = new File(inFileName);
- File stylesheet = new File(xslFileName);
-
- DocumentBuilder builder = factory.newDocumentBuilder();
- document = builder.parse(datafile);
-
- // Use a Transformer for output
- TransformerFactory tFactory =
- TransformerFactory.newInstance();
- StreamSource stylesource = new StreamSource(stylesheet);
- Transformer transformer = tFactory.newTransformer(stylesource);
- for (int ii = 0; ii < params.size(); ii += 2){
- transformer.setParameter((String) params.elementAt(ii),
- (String) params.elementAt(ii + 1));
- }
- DOMSource source = new DOMSource(document);
-
- PrintStream ps = new PrintStream( new FileOutputStream(outFileName));
- StreamResult result = new StreamResult(ps);
- transformer.transform(source, result);
-
- } catch (TransformerConfigurationException tce) {
- // Error generated by the parser
- System.out.println ("\n** Transformer Factory error");
- System.out.println(" " + tce.getMessage() );
+ final File datafile = new File(inFileName);
+ final File stylesheet = new File(xslFileName);
- // Use the contained exception, if any
- Throwable x = tce;
- if (tce.getException() != null)
- x = tce.getException();
- x.printStackTrace();
-
- } catch (TransformerException te) {
- // Error generated by the parser
- System.out.println ("\n** Transformation error");
- System.out.println(" " + te.getMessage() );
-
- // Use the contained exception, if any
- Throwable x = te;
- if (te.getException() != null)
- x = te.getException();
- x.printStackTrace();
-
- } catch (SAXException sxe) {
- // Error generated by this application
- // (or a parser-initialization error)
- Exception x = sxe;
- if (sxe.getException() != null)
- x = sxe.getException();
- x.printStackTrace();
-
- } catch (ParserConfigurationException pce) {
- // Parser with specified options can't be built
- pce.printStackTrace();
-
- } catch (IOException ioe) {
- // I/O error
- ioe.printStackTrace();
+ try (
+ final OutputStream os = new BufferedOutputStream(new FileOutputStream(outFileName));
+ ) {
+ final StreamSource stylesource = new StreamSource(stylesheet);
+ // Use a Transformer for output
+ final Transformer transformer =
+ TransformerFactory.newInstance().newTransformer(stylesource);
+ for (int ii = 0; ii < params.size(); ii += 2) {
+ transformer.setParameter(params.get(ii), params.get(ii + 1));
+ }
+ final DocumentBuilder builder = factory.newDocumentBuilder();
+ builder.setErrorHandler(new ErrorHandler() {
+ public void fatalError(SAXParseException exn) throws SAXException {
+ throw new SAXException(exn);
+ }
+ public void error(SAXParseException exn) throws SAXException {
+ fatalError(exn);
+ }
+ public void warning(SAXParseException exn) throws SAXException {
+ if (verbose) {
+ System.err.println("jvmtiGen warning: " + exn.getMessage());
+ }
+ }
+ });
+ final Document document = builder.parse(datafile);
+ final DOMSource source = new DOMSource(document);
+ final StreamResult result = new StreamResult(os);
+ transformer.transform(source, result);
+ } catch (IOException
+ | ParserConfigurationException
+ | SAXException
+ | TransformerException exn) {
+ System.err.print("jvmtiGen error: " + exn.getMessage());
+ exn.printStackTrace(System.err);
+ System.exit(EXIT_FAILURE_ERROR);
}
} // main
}
--- a/hotspot/src/share/vm/prims/whitebox.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/prims/whitebox.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -322,8 +322,8 @@
WB_END
WB_ENTRY(jboolean, WB_G1InConcurrentMark(JNIEnv* env, jobject o))
- G1CollectedHeap* g1 = G1CollectedHeap::heap();
- return g1->concurrent_mark()->cmThread()->during_cycle();
+ G1CollectedHeap* g1h = G1CollectedHeap::heap();
+ return g1h->concurrent_mark()->cmThread()->during_cycle();
WB_END
WB_ENTRY(jboolean, WB_G1StartMarkCycle(JNIEnv* env, jobject o))
--- a/hotspot/src/share/vm/runtime/arguments.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -364,6 +364,7 @@
{ "LazyBootClassLoader", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) },
{ "StarvationMonitorInterval", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) },
{ "PreInflateSpin", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) },
+ { "JNIDetachReleasesMonitors", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) },
#ifdef TEST_VERIFY_SPECIAL_JVM_FLAGS
{ "dep > obs", JDK_Version::jdk(9), JDK_Version::jdk(8), JDK_Version::undefined() },
@@ -817,9 +818,15 @@
int int_v;
intx intx_v;
bool is_neg = false;
+ Flag* result = Flag::find_flag(name, strlen(name));
+
+ if (result == NULL) {
+ return false;
+ }
+
// Check the sign first since atomull() parses only unsigned values.
if (*value == '-') {
- if ((CommandLineFlags::intxAt(name, &intx_v) != Flag::SUCCESS) && (CommandLineFlags::intAt(name, &int_v) != Flag::SUCCESS)) {
+ if (!result->is_intx() && !result->is_int()) {
return false;
}
value++;
@@ -828,37 +835,33 @@
if (!atomull(value, &v)) {
return false;
}
- int_v = (int) v;
- if (is_neg) {
- int_v = -int_v;
- }
- if (CommandLineFlags::intAtPut(name, &int_v, origin) == Flag::SUCCESS) {
- return true;
- }
- uint uint_v = (uint) v;
- if (!is_neg && CommandLineFlags::uintAtPut(name, &uint_v, origin) == Flag::SUCCESS) {
- return true;
- }
- intx_v = (intx) v;
- if (is_neg) {
- intx_v = -intx_v;
- }
- if (CommandLineFlags::intxAtPut(name, &intx_v, origin) == Flag::SUCCESS) {
- return true;
- }
- uintx uintx_v = (uintx) v;
- if (!is_neg && (CommandLineFlags::uintxAtPut(name, &uintx_v, origin) == Flag::SUCCESS)) {
- return true;
- }
- uint64_t uint64_t_v = (uint64_t) v;
- if (!is_neg && (CommandLineFlags::uint64_tAtPut(name, &uint64_t_v, origin) == Flag::SUCCESS)) {
- return true;
- }
- size_t size_t_v = (size_t) v;
- if (!is_neg && (CommandLineFlags::size_tAtPut(name, &size_t_v, origin) == Flag::SUCCESS)) {
- return true;
- }
- return false;
+ if (result->is_int()) {
+ int_v = (int) v;
+ if (is_neg) {
+ int_v = -int_v;
+ }
+ return CommandLineFlags::intAtPut(result, &int_v, origin) == Flag::SUCCESS;
+ } else if (result->is_uint()) {
+ uint uint_v = (uint) v;
+ return CommandLineFlags::uintAtPut(result, &uint_v, origin) == Flag::SUCCESS;
+ } else if (result->is_intx()) {
+ intx_v = (intx) v;
+ if (is_neg) {
+ intx_v = -intx_v;
+ }
+ return CommandLineFlags::intxAtPut(result, &intx_v, origin) == Flag::SUCCESS;
+ } else if (result->is_uintx()) {
+ uintx uintx_v = (uintx) v;
+ return CommandLineFlags::uintxAtPut(result, &uintx_v, origin) == Flag::SUCCESS;
+ } else if (result->is_uint64_t()) {
+ uint64_t uint64_t_v = (uint64_t) v;
+ return CommandLineFlags::uint64_tAtPut(result, &uint64_t_v, origin) == Flag::SUCCESS;
+ } else if (result->is_size_t()) {
+ size_t size_t_v = (size_t) v;
+ return CommandLineFlags::size_tAtPut(result, &size_t_v, origin) == Flag::SUCCESS;
+ } else {
+ return false;
+ }
}
static bool set_string_flag(const char* name, const char* value, Flag::Flags origin) {
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -34,10 +34,10 @@
#include "utilities/defaultStream.hpp"
Flag::Error AliasLevelConstraintFunc(intx value, bool verbose) {
- if ((value <= 1) && (Arguments::mode() == Arguments::_comp)) {
+ if ((value <= 1) && (Arguments::mode() == Arguments::_comp || Arguments::mode() == Arguments::_mixed)) {
CommandLineError::print(verbose,
"AliasLevel (" INTX_FORMAT ") is not "
- "compatible with -Xcomp \n",
+ "compatible with -Xcomp or -Xmixed\n",
value);
return Flag::VIOLATES_CONSTRAINT;
} else {
@@ -118,10 +118,10 @@
}
Flag::Error AllocatePrefetchStepSizeConstraintFunc(intx value, bool verbose) {
- if (value < 0 || value > max_jint) {
+ if (value < 1 || value > max_jint) {
CommandLineError::print(verbose,
"AllocatePrefetchStepSize (" INTX_FORMAT ") "
- "must be between 0 and %d\n",
+ "must be between 1 and %d\n",
AllocatePrefetchStepSize,
max_jint);
return Flag::VIOLATES_CONSTRAINT;
@@ -206,7 +206,7 @@
if (CodeCacheSegmentSize < (uintx)CodeEntryAlignment) {
CommandLineError::print(verbose,
"CodeCacheSegmentSize (" UINTX_FORMAT ") must be "
- "larger than or equal to CodeEntryAlignment (" INTX_FORMAT ")"
+ "larger than or equal to CodeEntryAlignment (" INTX_FORMAT ") "
"to align entry points\n",
CodeCacheSegmentSize, CodeEntryAlignment);
return Flag::VIOLATES_CONSTRAINT;
@@ -224,7 +224,7 @@
if (CodeCacheSegmentSize < (uintx)OptoLoopAlignment) {
CommandLineError::print(verbose,
"CodeCacheSegmentSize (" UINTX_FORMAT ") must be "
- "larger than or equal to OptoLoopAlignment (" INTX_FORMAT ")"
+ "larger than or equal to OptoLoopAlignment (" INTX_FORMAT ") "
"to align inner loops\n",
CodeCacheSegmentSize, OptoLoopAlignment);
return Flag::VIOLATES_CONSTRAINT;
@@ -235,15 +235,17 @@
}
Flag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose) {
- if (value < min_jint || value > max_jint) {
+#ifdef SOLARIS
+ if ((value < MinimumPriority || value > MaximumPriority) &&
+ (value != -1) && (value != -FXCriticalPriority)) {
CommandLineError::print(verbose,
- "CompileThreadPriority (" INTX_FORMAT ") "
- "must be between %d and %d. "
- "Please also make sure to specify values that are "
- "meaningful to your operating system\n",
- value, min_jint, max_jint);
+ "CompileThreadPriority (" INTX_FORMAT ") must be "
+ "between %d and %d inclusively or -1 (means no change) "
+ "or %d (special value for critical thread class/priority)\n",
+ value, MinimumPriority, MaximumPriority, -FXCriticalPriority);
return Flag::VIOLATES_CONSTRAINT;
}
+#endif
return Flag::SUCCESS;
}
@@ -277,14 +279,6 @@
}
Flag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose) {
- if (value < 0 || value > 16) {
- CommandLineError::print(verbose,
- "OptoLoopAlignment (" INTX_FORMAT ") "
- "must be between 0 and 16\n",
- value);
- return Flag::VIOLATES_CONSTRAINT;
- }
-
if (!is_power_of_2(value)) {
CommandLineError::print(verbose,
"OptoLoopAlignment (" INTX_FORMAT ") "
@@ -308,7 +302,8 @@
Flag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verbose) {
if (value != 0) {
CommandLineError::print(verbose,
- "ArraycopyDstPrefetchDistance (" INTX_FORMAT ") must be 0\n");
+ "ArraycopyDstPrefetchDistance (" UINTX_FORMAT ") must be 0\n",
+ value);
return Flag::VIOLATES_CONSTRAINT;
}
@@ -318,7 +313,8 @@
Flag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose) {
if (value != 0) {
CommandLineError::print(verbose,
- "ArraycopySrcPrefetchDistance (" INTX_FORMAT ") must be 0\n");
+ "ArraycopySrcPrefetchDistance (" UINTX_FORMAT ") must be 0\n",
+ value);
return Flag::VIOLATES_CONSTRAINT;
}
--- a/hotspot/src/share/vm/runtime/deoptimization.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/runtime/deoptimization.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -2062,6 +2062,7 @@
// This is used for debugging and diagnostics, including LogFile output.
const char* Deoptimization::format_trap_state(char* buf, size_t buflen,
int trap_state) {
+ assert(buflen > 0, "sanity");
DeoptReason reason = trap_state_reason(trap_state);
bool recomp_flag = trap_state_is_recompiled(trap_state);
// Re-encode the state from its decoded components.
@@ -2082,8 +2083,6 @@
trap_reason_name(reason),
recomp_flag ? " recompiled" : "");
}
- if (len >= buflen)
- buf[buflen-1] = '\0';
return buf;
}
@@ -2178,8 +2177,6 @@
#endif
);
}
- if (len >= buflen)
- buf[buflen-1] = '\0';
return buf;
}
--- a/hotspot/src/share/vm/runtime/globals.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/runtime/globals.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -787,7 +787,7 @@
e.commit();
}
-static Flag::Error apply_constraint_and_check_range_bool(const char* name, bool new_value, bool verbose = true) {
+static Flag::Error apply_constraint_and_check_range_bool(const char* name, bool new_value, bool verbose) {
Flag::Error status = Flag::SUCCESS;
CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name);
if (constraint != NULL) {
@@ -804,32 +804,33 @@
return Flag::SUCCESS;
}
-Flag::Error CommandLineFlags::boolAtPut(const char* name, size_t len, bool* value, Flag::Flags origin) {
- Flag* result = Flag::find_flag(name, len);
- if (result == NULL) return Flag::INVALID_FLAG;
- if (!result->is_bool()) return Flag::WRONG_FORMAT;
+Flag::Error CommandLineFlags::boolAtPut(Flag* flag, bool* value, Flag::Flags origin) {
+ const char* name;
+ if (flag == NULL) return Flag::INVALID_FLAG;
+ if (!flag->is_bool()) return Flag::WRONG_FORMAT;
+ name = flag->_name;
Flag::Error check = apply_constraint_and_check_range_bool(name, *value, !CommandLineFlagConstraintList::validated_after_ergo());
if (check != Flag::SUCCESS) return check;
- bool old_value = result->get_bool();
+ bool old_value = flag->get_bool();
trace_flag_changed<EventBooleanFlagChanged, bool>(name, old_value, *value, origin);
- result->set_bool(*value);
+ flag->set_bool(*value);
*value = old_value;
- result->set_origin(origin);
+ flag->set_origin(origin);
return Flag::SUCCESS;
}
+Flag::Error CommandLineFlags::boolAtPut(const char* name, size_t len, bool* value, Flag::Flags origin) {
+ Flag* result = Flag::find_flag(name, len);
+ return boolAtPut(result, value, origin);
+}
+
Flag::Error CommandLineFlagsEx::boolAtPut(CommandLineFlagWithType flag, bool value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_bool(), "wrong flag type");
- Flag::Error check = apply_constraint_and_check_range_bool(faddr->_name, value);
- if (check != Flag::SUCCESS) return check;
- trace_flag_changed<EventBooleanFlagChanged, bool>(faddr->_name, faddr->get_bool(), value, origin);
- faddr->set_bool(value);
- faddr->set_origin(origin);
- return Flag::SUCCESS;
+ return CommandLineFlags::boolAtPut(faddr, &value, origin);
}
-static Flag::Error apply_constraint_and_check_range_int(const char* name, int new_value, bool verbose = true) {
+static Flag::Error apply_constraint_and_check_range_int(const char* name, int new_value, bool verbose) {
Flag::Error status = Flag::SUCCESS;
CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
if (range != NULL) {
@@ -852,32 +853,33 @@
return Flag::SUCCESS;
}
-Flag::Error CommandLineFlags::intAtPut(const char* name, size_t len, int* value, Flag::Flags origin) {
- Flag* result = Flag::find_flag(name, len);
- if (result == NULL) return Flag::INVALID_FLAG;
- if (!result->is_int()) return Flag::WRONG_FORMAT;
+Flag::Error CommandLineFlags::intAtPut(Flag* flag, int* value, Flag::Flags origin) {
+ const char* name;
+ if (flag == NULL) return Flag::INVALID_FLAG;
+ if (!flag->is_int()) return Flag::WRONG_FORMAT;
+ name = flag->_name;
Flag::Error check = apply_constraint_and_check_range_int(name, *value, !CommandLineFlagConstraintList::validated_after_ergo());
if (check != Flag::SUCCESS) return check;
- int old_value = result->get_int();
+ int old_value = flag->get_int();
trace_flag_changed<EventIntFlagChanged, s4>(name, old_value, *value, origin);
- result->set_int(*value);
+ flag->set_int(*value);
*value = old_value;
- result->set_origin(origin);
+ flag->set_origin(origin);
return Flag::SUCCESS;
}
+Flag::Error CommandLineFlags::intAtPut(const char* name, size_t len, int* value, Flag::Flags origin) {
+ Flag* result = Flag::find_flag(name, len);
+ return intAtPut(result, value, origin);
+}
+
Flag::Error CommandLineFlagsEx::intAtPut(CommandLineFlagWithType flag, int value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_int(), "wrong flag type");
- Flag::Error check = apply_constraint_and_check_range_int(faddr->_name, value, !CommandLineFlagConstraintList::validated_after_ergo());
- if (check != Flag::SUCCESS) return check;
- trace_flag_changed<EventIntFlagChanged, s4>(faddr->_name, faddr->get_int(), value, origin);
- faddr->set_int(value);
- faddr->set_origin(origin);
- return Flag::SUCCESS;
+ return CommandLineFlags::intAtPut(faddr, &value, origin);
}
-static Flag::Error apply_constraint_and_check_range_uint(const char* name, uint new_value, bool verbose = true) {
+static Flag::Error apply_constraint_and_check_range_uint(const char* name, uint new_value, bool verbose) {
Flag::Error status = Flag::SUCCESS;
CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
if (range != NULL) {
@@ -900,29 +902,30 @@
return Flag::SUCCESS;
}
-Flag::Error CommandLineFlags::uintAtPut(const char* name, size_t len, uint* value, Flag::Flags origin) {
- Flag* result = Flag::find_flag(name, len);
- if (result == NULL) return Flag::INVALID_FLAG;
- if (!result->is_uint()) return Flag::WRONG_FORMAT;
+Flag::Error CommandLineFlags::uintAtPut(Flag* flag, uint* value, Flag::Flags origin) {
+ const char* name;
+ if (flag == NULL) return Flag::INVALID_FLAG;
+ if (!flag->is_uint()) return Flag::WRONG_FORMAT;
+ name = flag->_name;
Flag::Error check = apply_constraint_and_check_range_uint(name, *value, !CommandLineFlagConstraintList::validated_after_ergo());
if (check != Flag::SUCCESS) return check;
- uint old_value = result->get_uint();
+ uint old_value = flag->get_uint();
trace_flag_changed<EventUnsignedIntFlagChanged, u4>(name, old_value, *value, origin);
- result->set_uint(*value);
+ flag->set_uint(*value);
*value = old_value;
- result->set_origin(origin);
+ flag->set_origin(origin);
return Flag::SUCCESS;
}
+Flag::Error CommandLineFlags::uintAtPut(const char* name, size_t len, uint* value, Flag::Flags origin) {
+ Flag* result = Flag::find_flag(name, len);
+ return uintAtPut(result, value, origin);
+}
+
Flag::Error CommandLineFlagsEx::uintAtPut(CommandLineFlagWithType flag, uint value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_uint(), "wrong flag type");
- Flag::Error check = apply_constraint_and_check_range_uint(faddr->_name, value, !CommandLineFlagConstraintList::validated_after_ergo());
- if (check != Flag::SUCCESS) return check;
- trace_flag_changed<EventUnsignedIntFlagChanged, u4>(faddr->_name, faddr->get_uint(), value, origin);
- faddr->set_uint(value);
- faddr->set_origin(origin);
- return Flag::SUCCESS;
+ return CommandLineFlags::uintAtPut(faddr, &value, origin);
}
Flag::Error CommandLineFlags::intxAt(const char* name, size_t len, intx* value, bool allow_locked, bool return_flag) {
@@ -933,7 +936,7 @@
return Flag::SUCCESS;
}
-static Flag::Error apply_constraint_and_check_range_intx(const char* name, intx new_value, bool verbose = true) {
+static Flag::Error apply_constraint_and_check_range_intx(const char* name, intx new_value, bool verbose) {
Flag::Error status = Flag::SUCCESS;
CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
if (range != NULL) {
@@ -948,29 +951,30 @@
return status;
}
-Flag::Error CommandLineFlags::intxAtPut(const char* name, size_t len, intx* value, Flag::Flags origin) {
- Flag* result = Flag::find_flag(name, len);
- if (result == NULL) return Flag::INVALID_FLAG;
- if (!result->is_intx()) return Flag::WRONG_FORMAT;
+Flag::Error CommandLineFlags::intxAtPut(Flag* flag, intx* value, Flag::Flags origin) {
+ const char* name;
+ if (flag == NULL) return Flag::INVALID_FLAG;
+ if (!flag->is_intx()) return Flag::WRONG_FORMAT;
+ name = flag->_name;
Flag::Error check = apply_constraint_and_check_range_intx(name, *value, !CommandLineFlagConstraintList::validated_after_ergo());
if (check != Flag::SUCCESS) return check;
- intx old_value = result->get_intx();
+ intx old_value = flag->get_intx();
trace_flag_changed<EventLongFlagChanged, intx>(name, old_value, *value, origin);
- result->set_intx(*value);
+ flag->set_intx(*value);
*value = old_value;
- result->set_origin(origin);
+ flag->set_origin(origin);
return Flag::SUCCESS;
}
+Flag::Error CommandLineFlags::intxAtPut(const char* name, size_t len, intx* value, Flag::Flags origin) {
+ Flag* result = Flag::find_flag(name, len);
+ return intxAtPut(result, value, origin);
+}
+
Flag::Error CommandLineFlagsEx::intxAtPut(CommandLineFlagWithType flag, intx value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_intx(), "wrong flag type");
- Flag::Error check = apply_constraint_and_check_range_intx(faddr->_name, value);
- if (check != Flag::SUCCESS) return check;
- trace_flag_changed<EventLongFlagChanged, intx>(faddr->_name, faddr->get_intx(), value, origin);
- faddr->set_intx(value);
- faddr->set_origin(origin);
- return Flag::SUCCESS;
+ return CommandLineFlags::intxAtPut(faddr, &value, origin);
}
Flag::Error CommandLineFlags::uintxAt(const char* name, size_t len, uintx* value, bool allow_locked, bool return_flag) {
@@ -981,7 +985,7 @@
return Flag::SUCCESS;
}
-static Flag::Error apply_constraint_and_check_range_uintx(const char* name, uintx new_value, bool verbose = true) {
+static Flag::Error apply_constraint_and_check_range_uintx(const char* name, uintx new_value, bool verbose) {
Flag::Error status = Flag::SUCCESS;
CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
if (range != NULL) {
@@ -996,29 +1000,30 @@
return status;
}
-Flag::Error CommandLineFlags::uintxAtPut(const char* name, size_t len, uintx* value, Flag::Flags origin) {
- Flag* result = Flag::find_flag(name, len);
- if (result == NULL) return Flag::INVALID_FLAG;
- if (!result->is_uintx()) return Flag::WRONG_FORMAT;
+Flag::Error CommandLineFlags::uintxAtPut(Flag* flag, uintx* value, Flag::Flags origin) {
+ const char* name;
+ if (flag == NULL) return Flag::INVALID_FLAG;
+ if (!flag->is_uintx()) return Flag::WRONG_FORMAT;
+ name = flag->_name;
Flag::Error check = apply_constraint_and_check_range_uintx(name, *value, !CommandLineFlagConstraintList::validated_after_ergo());
if (check != Flag::SUCCESS) return check;
- uintx old_value = result->get_uintx();
+ uintx old_value = flag->get_uintx();
trace_flag_changed<EventUnsignedLongFlagChanged, u8>(name, old_value, *value, origin);
- result->set_uintx(*value);
+ flag->set_uintx(*value);
*value = old_value;
- result->set_origin(origin);
+ flag->set_origin(origin);
return Flag::SUCCESS;
}
+Flag::Error CommandLineFlags::uintxAtPut(const char* name, size_t len, uintx* value, Flag::Flags origin) {
+ Flag* result = Flag::find_flag(name, len);
+ return uintxAtPut(result, value, origin);
+}
+
Flag::Error CommandLineFlagsEx::uintxAtPut(CommandLineFlagWithType flag, uintx value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_uintx(), "wrong flag type");
- Flag::Error check = apply_constraint_and_check_range_uintx(faddr->_name, value);
- if (check != Flag::SUCCESS) return check;
- trace_flag_changed<EventUnsignedLongFlagChanged, u8>(faddr->_name, faddr->get_uintx(), value, origin);
- faddr->set_uintx(value);
- faddr->set_origin(origin);
- return Flag::SUCCESS;
+ return CommandLineFlags::uintxAtPut(faddr, &value, origin);
}
Flag::Error CommandLineFlags::uint64_tAt(const char* name, size_t len, uint64_t* value, bool allow_locked, bool return_flag) {
@@ -1029,7 +1034,7 @@
return Flag::SUCCESS;
}
-static Flag::Error apply_constraint_and_check_range_uint64_t(const char* name, uint64_t new_value, bool verbose = true) {
+static Flag::Error apply_constraint_and_check_range_uint64_t(const char* name, uint64_t new_value, bool verbose) {
Flag::Error status = Flag::SUCCESS;
CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
if (range != NULL) {
@@ -1044,29 +1049,30 @@
return status;
}
-Flag::Error CommandLineFlags::uint64_tAtPut(const char* name, size_t len, uint64_t* value, Flag::Flags origin) {
- Flag* result = Flag::find_flag(name, len);
- if (result == NULL) return Flag::INVALID_FLAG;
- if (!result->is_uint64_t()) return Flag::WRONG_FORMAT;
+Flag::Error CommandLineFlags::uint64_tAtPut(Flag* flag, uint64_t* value, Flag::Flags origin) {
+ const char* name;
+ if (flag == NULL) return Flag::INVALID_FLAG;
+ if (!flag->is_uint64_t()) return Flag::WRONG_FORMAT;
+ name = flag->_name;
Flag::Error check = apply_constraint_and_check_range_uint64_t(name, *value, !CommandLineFlagConstraintList::validated_after_ergo());
if (check != Flag::SUCCESS) return check;
- uint64_t old_value = result->get_uint64_t();
+ uint64_t old_value = flag->get_uint64_t();
trace_flag_changed<EventUnsignedLongFlagChanged, u8>(name, old_value, *value, origin);
- result->set_uint64_t(*value);
+ flag->set_uint64_t(*value);
*value = old_value;
- result->set_origin(origin);
+ flag->set_origin(origin);
return Flag::SUCCESS;
}
+Flag::Error CommandLineFlags::uint64_tAtPut(const char* name, size_t len, uint64_t* value, Flag::Flags origin) {
+ Flag* result = Flag::find_flag(name, len);
+ return uint64_tAtPut(result, value, origin);
+}
+
Flag::Error CommandLineFlagsEx::uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_uint64_t(), "wrong flag type");
- Flag::Error check = apply_constraint_and_check_range_uint64_t(faddr->_name, value);
- if (check != Flag::SUCCESS) return check;
- trace_flag_changed<EventUnsignedLongFlagChanged, u8>(faddr->_name, faddr->get_uint64_t(), value, origin);
- faddr->set_uint64_t(value);
- faddr->set_origin(origin);
- return Flag::SUCCESS;
+ return CommandLineFlags::uint64_tAtPut(faddr, &value, origin);
}
Flag::Error CommandLineFlags::size_tAt(const char* name, size_t len, size_t* value, bool allow_locked, bool return_flag) {
@@ -1077,7 +1083,7 @@
return Flag::SUCCESS;
}
-static Flag::Error apply_constraint_and_check_range_size_t(const char* name, size_t new_value, bool verbose = true) {
+static Flag::Error apply_constraint_and_check_range_size_t(const char* name, size_t new_value, bool verbose) {
Flag::Error status = Flag::SUCCESS;
CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
if (range != NULL) {
@@ -1092,29 +1098,31 @@
return status;
}
-Flag::Error CommandLineFlags::size_tAtPut(const char* name, size_t len, size_t* value, Flag::Flags origin) {
- Flag* result = Flag::find_flag(name, len);
- if (result == NULL) return Flag::INVALID_FLAG;
- if (!result->is_size_t()) return Flag::WRONG_FORMAT;
+
+Flag::Error CommandLineFlags::size_tAtPut(Flag* flag, size_t* value, Flag::Flags origin) {
+ const char* name;
+ if (flag == NULL) return Flag::INVALID_FLAG;
+ if (!flag->is_size_t()) return Flag::WRONG_FORMAT;
+ name = flag->_name;
Flag::Error check = apply_constraint_and_check_range_size_t(name, *value, !CommandLineFlagConstraintList::validated_after_ergo());
if (check != Flag::SUCCESS) return check;
- size_t old_value = result->get_size_t();
+ size_t old_value = flag->get_size_t();
trace_flag_changed<EventUnsignedLongFlagChanged, u8>(name, old_value, *value, origin);
- result->set_size_t(*value);
+ flag->set_size_t(*value);
*value = old_value;
- result->set_origin(origin);
+ flag->set_origin(origin);
return Flag::SUCCESS;
}
+Flag::Error CommandLineFlags::size_tAtPut(const char* name, size_t len, size_t* value, Flag::Flags origin) {
+ Flag* result = Flag::find_flag(name, len);
+ return size_tAtPut(result, value, origin);
+}
+
Flag::Error CommandLineFlagsEx::size_tAtPut(CommandLineFlagWithType flag, size_t value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_size_t(), "wrong flag type");
- Flag::Error check = apply_constraint_and_check_range_size_t(faddr->_name, value);
- if (check != Flag::SUCCESS) return check;
- trace_flag_changed<EventUnsignedLongFlagChanged, u8>(faddr->_name, faddr->get_size_t(), value, origin);
- faddr->set_size_t(value);
- faddr->set_origin(origin);
- return Flag::SUCCESS;
+ return CommandLineFlags::size_tAtPut(faddr, &value, origin);
}
Flag::Error CommandLineFlags::doubleAt(const char* name, size_t len, double* value, bool allow_locked, bool return_flag) {
@@ -1125,7 +1133,7 @@
return Flag::SUCCESS;
}
-static Flag::Error apply_constraint_and_check_range_double(const char* name, double new_value, bool verbose = true) {
+static Flag::Error apply_constraint_and_check_range_double(const char* name, double new_value, bool verbose) {
Flag::Error status = Flag::SUCCESS;
CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
if (range != NULL) {
@@ -1140,29 +1148,30 @@
return status;
}
-Flag::Error CommandLineFlags::doubleAtPut(const char* name, size_t len, double* value, Flag::Flags origin) {
- Flag* result = Flag::find_flag(name, len);
- if (result == NULL) return Flag::INVALID_FLAG;
- if (!result->is_double()) return Flag::WRONG_FORMAT;
+Flag::Error CommandLineFlags::doubleAtPut(Flag* flag, double* value, Flag::Flags origin) {
+ const char* name;
+ if (flag == NULL) return Flag::INVALID_FLAG;
+ if (!flag->is_double()) return Flag::WRONG_FORMAT;
+ name = flag->_name;
Flag::Error check = apply_constraint_and_check_range_double(name, *value, !CommandLineFlagConstraintList::validated_after_ergo());
if (check != Flag::SUCCESS) return check;
- double old_value = result->get_double();
+ double old_value = flag->get_double();
trace_flag_changed<EventDoubleFlagChanged, double>(name, old_value, *value, origin);
- result->set_double(*value);
+ flag->set_double(*value);
*value = old_value;
- result->set_origin(origin);
+ flag->set_origin(origin);
return Flag::SUCCESS;
}
+Flag::Error CommandLineFlags::doubleAtPut(const char* name, size_t len, double* value, Flag::Flags origin) {
+ Flag* result = Flag::find_flag(name, len);
+ return doubleAtPut(result, value, origin);
+}
+
Flag::Error CommandLineFlagsEx::doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_double(), "wrong flag type");
- Flag::Error check = apply_constraint_and_check_range_double(faddr->_name, value);
- if (check != Flag::SUCCESS) return check;
- trace_flag_changed<EventDoubleFlagChanged, double>(faddr->_name, faddr->get_double(), value, origin);
- faddr->set_double(value);
- faddr->set_origin(origin);
- return Flag::SUCCESS;
+ return CommandLineFlags::doubleAtPut(faddr, &value, origin);
}
Flag::Error CommandLineFlags::ccstrAt(const char* name, size_t len, ccstr* value, bool allow_locked, bool return_flag) {
--- a/hotspot/src/share/vm/runtime/globals.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -452,41 +452,49 @@
public:
static Flag::Error boolAt(const char* name, size_t len, bool* value, bool allow_locked = false, bool return_flag = false);
static Flag::Error boolAt(const char* name, bool* value, bool allow_locked = false, bool return_flag = false) { return boolAt(name, strlen(name), value, allow_locked, return_flag); }
+ static Flag::Error boolAtPut(Flag* flag, bool* value, Flag::Flags origin);
static Flag::Error boolAtPut(const char* name, size_t len, bool* value, Flag::Flags origin);
static Flag::Error boolAtPut(const char* name, bool* value, Flag::Flags origin) { return boolAtPut(name, strlen(name), value, origin); }
static Flag::Error intAt(const char* name, size_t len, int* value, bool allow_locked = false, bool return_flag = false);
static Flag::Error intAt(const char* name, int* value, bool allow_locked = false, bool return_flag = false) { return intAt(name, strlen(name), value, allow_locked, return_flag); }
+ static Flag::Error intAtPut(Flag* flag, int* value, Flag::Flags origin);
static Flag::Error intAtPut(const char* name, size_t len, int* value, Flag::Flags origin);
static Flag::Error intAtPut(const char* name, int* value, Flag::Flags origin) { return intAtPut(name, strlen(name), value, origin); }
static Flag::Error uintAt(const char* name, size_t len, uint* value, bool allow_locked = false, bool return_flag = false);
static Flag::Error uintAt(const char* name, uint* value, bool allow_locked = false, bool return_flag = false) { return uintAt(name, strlen(name), value, allow_locked, return_flag); }
+ static Flag::Error uintAtPut(Flag* flag, uint* value, Flag::Flags origin);
static Flag::Error uintAtPut(const char* name, size_t len, uint* value, Flag::Flags origin);
static Flag::Error uintAtPut(const char* name, uint* value, Flag::Flags origin) { return uintAtPut(name, strlen(name), value, origin); }
static Flag::Error intxAt(const char* name, size_t len, intx* value, bool allow_locked = false, bool return_flag = false);
static Flag::Error intxAt(const char* name, intx* value, bool allow_locked = false, bool return_flag = false) { return intxAt(name, strlen(name), value, allow_locked, return_flag); }
+ static Flag::Error intxAtPut(Flag* flag, intx* value, Flag::Flags origin);
static Flag::Error intxAtPut(const char* name, size_t len, intx* value, Flag::Flags origin);
static Flag::Error intxAtPut(const char* name, intx* value, Flag::Flags origin) { return intxAtPut(name, strlen(name), value, origin); }
static Flag::Error uintxAt(const char* name, size_t len, uintx* value, bool allow_locked = false, bool return_flag = false);
static Flag::Error uintxAt(const char* name, uintx* value, bool allow_locked = false, bool return_flag = false) { return uintxAt(name, strlen(name), value, allow_locked, return_flag); }
+ static Flag::Error uintxAtPut(Flag* flag, uintx* value, Flag::Flags origin);
static Flag::Error uintxAtPut(const char* name, size_t len, uintx* value, Flag::Flags origin);
static Flag::Error uintxAtPut(const char* name, uintx* value, Flag::Flags origin) { return uintxAtPut(name, strlen(name), value, origin); }
static Flag::Error size_tAt(const char* name, size_t len, size_t* value, bool allow_locked = false, bool return_flag = false);
static Flag::Error size_tAt(const char* name, size_t* value, bool allow_locked = false, bool return_flag = false) { return size_tAt(name, strlen(name), value, allow_locked, return_flag); }
+ static Flag::Error size_tAtPut(Flag* flag, size_t* value, Flag::Flags origin);
static Flag::Error size_tAtPut(const char* name, size_t len, size_t* value, Flag::Flags origin);
static Flag::Error size_tAtPut(const char* name, size_t* value, Flag::Flags origin) { return size_tAtPut(name, strlen(name), value, origin); }
static Flag::Error uint64_tAt(const char* name, size_t len, uint64_t* value, bool allow_locked = false, bool return_flag = false);
static Flag::Error uint64_tAt(const char* name, uint64_t* value, bool allow_locked = false, bool return_flag = false) { return uint64_tAt(name, strlen(name), value, allow_locked, return_flag); }
+ static Flag::Error uint64_tAtPut(Flag* flag, uint64_t* value, Flag::Flags origin);
static Flag::Error uint64_tAtPut(const char* name, size_t len, uint64_t* value, Flag::Flags origin);
static Flag::Error uint64_tAtPut(const char* name, uint64_t* value, Flag::Flags origin) { return uint64_tAtPut(name, strlen(name), value, origin); }
static Flag::Error doubleAt(const char* name, size_t len, double* value, bool allow_locked = false, bool return_flag = false);
static Flag::Error doubleAt(const char* name, double* value, bool allow_locked = false, bool return_flag = false) { return doubleAt(name, strlen(name), value, allow_locked, return_flag); }
+ static Flag::Error doubleAtPut(Flag* flag, double* value, Flag::Flags origin);
static Flag::Error doubleAtPut(const char* name, size_t len, double* value, Flag::Flags origin);
static Flag::Error doubleAtPut(const char* name, double* value, Flag::Flags origin) { return doubleAtPut(name, strlen(name), value, origin); }
@@ -1333,9 +1341,6 @@
product(bool, AllowJNIEnvProxy, false, \
"Allow JNIEnv proxies for jdbx") \
\
- product(bool, JNIDetachReleasesMonitors, true, \
- "JNI DetachCurrentThread releases monitors owned by thread") \
- \
product(bool, RestoreMXCSROnJNICalls, false, \
"Restore MXCSR when returning from JNI calls") \
\
@@ -1501,9 +1506,6 @@
develop(bool, TraceOopMapRewrites, false, \
"Trace rewriting of method oops during oop map generation") \
\
- develop(bool, TraceSafepoint, false, \
- "Trace safepoint operations") \
- \
develop(bool, TraceICBuffer, false, \
"Trace usage of IC buffer") \
\
@@ -2075,6 +2077,10 @@
"unloading of classes when class unloading is enabled") \
range(0, 100) \
\
+ develop(bool, CMSTestInFreeList, false, \
+ "Check if the coalesced range is already in the " \
+ "free lists as claimed") \
+ \
notproduct(bool, CMSVerifyReturnedBytes, false, \
"Check that all the garbage collected was returned to the " \
"free lists") \
@@ -3091,6 +3097,7 @@
\
product(intx, AllocatePrefetchStepSize, 16, \
"Step size in bytes of sequential prefetch instructions") \
+ range(1, max_jint) \
constraint(AllocatePrefetchStepSizeConstraintFunc,AfterMemoryInit)\
\
product(intx, AllocatePrefetchInstr, 0, \
@@ -3574,6 +3581,7 @@
\
product_pd(intx, OptoLoopAlignment, \
"Align inner loops to zero relative to this modulus") \
+ range(1, 16) \
constraint(OptoLoopAlignmentConstraintFunc, AfterErgo) \
\
product_pd(uintx, InitialCodeCacheSize, \
@@ -3738,6 +3746,7 @@
product(intx, CompilerThreadPriority, -1, \
"The native priority at which compiler threads should run " \
"(-1 means no change)") \
+ range(min_jint, max_jint) \
constraint(CompilerThreadPriorityConstraintFunc, AfterErgo) \
\
product(intx, VMThreadPriority, -1, \
@@ -4203,9 +4212,6 @@
diagnostic(bool, StringDeduplicationRehashALot, false, \
"Force table rehash every time the table is scanned") \
\
- develop(bool, TraceDefaultMethods, false, \
- "Trace the default method processing steps") \
- \
diagnostic(bool, WhiteBoxAPI, false, \
"Enable internal testing APIs") \
\
--- a/hotspot/src/share/vm/runtime/os.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/runtime/os.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -32,6 +32,7 @@
#include "code/vtableStubs.hpp"
#include "gc/shared/vmGCOperations.hpp"
#include "interpreter/interpreter.hpp"
+#include "logging/log.hpp"
#include "memory/allocation.inline.hpp"
#ifdef ASSERT
#include "memory/guardedMemory.hpp"
@@ -1363,9 +1364,8 @@
// thread tries to store to the "read-only" memory serialize page during state
// transition.
void os::block_on_serialize_page_trap() {
- if (TraceSafepoint) {
- tty->print_cr("Block until the serialize page permission restored");
- }
+ log_debug(safepoint)("Block until the serialize page permission restored");
+
// When VMThread is holding the SerializePageLock during modifying the
// access permission of the memory serialize page, the following call
// will block until the permission of that page is restored to rw.
--- a/hotspot/src/share/vm/runtime/os.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/runtime/os.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -589,6 +589,9 @@
static void *find_agent_function(AgentLibrary *agent_lib, bool check_lib,
const char *syms[], size_t syms_len);
+ // Write to stream
+ static int log_vsnprintf(char* buf, size_t len, const char* fmt, va_list args) ATTRIBUTE_PRINTF(3, 0);
+
// Print out system information; they are called by fatal error handler.
// Output format may be different on different platforms.
static void print_os_info(outputStream* st);
--- a/hotspot/src/share/vm/runtime/safepoint.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/runtime/safepoint.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -33,6 +33,7 @@
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/gcLocker.inline.hpp"
#include "interpreter/interpreter.hpp"
+#include "logging/log.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.inline.hpp"
#include "oops/oop.inline.hpp"
@@ -104,9 +105,7 @@
int nof_threads = Threads::number_of_threads();
- if (TraceSafepoint) {
- tty->print_cr("Safepoint synchronization initiated. (%d)", nof_threads);
- }
+ log_debug(safepoint)("Safepoint synchronization initiated. (%d)", nof_threads);
RuntimeService::record_safepoint_begin();
@@ -219,7 +218,10 @@
// steps = MIN(steps, 2000-100)
// if (iterations != 0) steps -= NNN
}
- if (TraceSafepoint && Verbose) cur_state->print();
+ if (log_is_enabled(Trace, safepoint)) {
+ ResourceMark rm;
+ cur_state->print_on(LogHandle(safepoint)::debug_stream());
+ }
}
}
@@ -316,7 +318,7 @@
// wait until all threads are stopped
while (_waiting_to_block > 0) {
- if (TraceSafepoint) tty->print_cr("Waiting for %d thread(s) to block", _waiting_to_block);
+ log_debug(safepoint)("Waiting for %d thread(s) to block", _waiting_to_block);
if (!SafepointTimeout || timeout_error_printed) {
Safepoint_lock->wait(true); // true, means with no safepoint checks
} else {
@@ -362,9 +364,10 @@
// Update the count of active JNI critical regions
GC_locker::set_jni_lock_count(_current_jni_active_count);
- if (TraceSafepoint) {
+ if (log_is_enabled(Debug, safepoint)) {
VM_Operation *op = VMThread::vm_operation();
- tty->print_cr("Entering safepoint region: %s", (op != NULL) ? op->name() : "no vm operation");
+ log_debug(safepoint)("Entering safepoint region: %s",
+ (op != NULL) ? op->name() : "no vm operation");
}
RuntimeService::record_safepoint_synchronized();
@@ -428,9 +431,7 @@
_state = _not_synchronized;
OrderAccess::fence();
- if (TraceSafepoint) {
- tty->print_cr("Leaving safepoint region");
- }
+ log_debug(safepoint)("Leaving safepoint region");
// Start suspended threads
for(JavaThread *current = Threads::first(); current; current = current->next()) {
@@ -919,7 +920,6 @@
_thread->print_thread_state_on(st);
}
-
// ---------------------------------------------------------------------------------------------------------------------
// Block the thread at the safepoint poll or poll return.
--- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -37,6 +37,7 @@
#include "gc/shared/gcLocker.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
+#include "logging/log.hpp"
#include "memory/universe.inline.hpp"
#include "oops/oop.inline.hpp"
#include "prims/forte.hpp"
@@ -556,17 +557,10 @@
"polling page safepoint stub not created yet");
stub = SharedRuntime::polling_page_safepoint_handler_blob()->entry_point();
}
-#ifndef PRODUCT
- if (TraceSafepoint) {
- char buf[256];
- jio_snprintf(buf, sizeof(buf),
- "... found polling page %s exception at pc = "
- INTPTR_FORMAT ", stub =" INTPTR_FORMAT,
- at_poll_return ? "return" : "loop",
- (intptr_t)pc, (intptr_t)stub);
- tty->print_raw_cr(buf);
- }
-#endif // PRODUCT
+ log_debug(safepoint)("... found polling page %s exception at pc = "
+ INTPTR_FORMAT ", stub =" INTPTR_FORMAT,
+ at_poll_return ? "return" : "loop",
+ (intptr_t)pc, (intptr_t)stub);
return stub;
}
--- a/hotspot/src/share/vm/runtime/task.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/runtime/task.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -117,8 +117,9 @@
if (_num_tasks == PeriodicTask::max_tasks) {
fatal("Overflow in PeriodicTask table");
+ } else {
+ _tasks[_num_tasks++] = this;
}
- _tasks[_num_tasks++] = this;
WatcherThread* thread = WatcherThread::watcher_thread();
if (thread != NULL) {
--- a/hotspot/src/share/vm/runtime/thread.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/runtime/thread.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -1868,13 +1868,10 @@
// Optionally release any monitors for regular JavaThread exits. This
// is provided as a work around for any bugs in monitor enter-exit
// matching. This can be expensive so it is not enabled by default.
- // ObjectMonitor::Knob_ExitRelease is a superset of the
- // JNIDetachReleasesMonitors option.
//
// ensure_join() ignores IllegalThreadStateExceptions, and so does
// ObjectSynchronizer::release_monitors_owned_by_thread().
- if ((exit_type == jni_detach && JNIDetachReleasesMonitors) ||
- ObjectMonitor::Knob_ExitRelease) {
+ if (exit_type == jni_detach || ObjectMonitor::Knob_ExitRelease) {
// Sanity check even though JNI DetachCurrentThread() would have
// returned JNI_ERR if there was a Java frame. JavaThread exit
// should be done executing Java code by the time we get here.
@@ -1941,7 +1938,7 @@
assert(!SafepointSynchronize::is_at_safepoint(),
"we should not be at a safepoint");
- ObjPtrQueue& satb_queue = satb_mark_queue();
+ SATBMarkQueue& satb_queue = satb_mark_queue();
SATBMarkQueueSet& satb_queue_set = satb_mark_queue_set();
// The SATB queue should have been constructed with its active
// field set to false.
--- a/hotspot/src/share/vm/runtime/thread.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/runtime/thread.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -49,7 +49,7 @@
#include "utilities/top.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/dirtyCardQueue.hpp"
-#include "gc/g1/satbQueue.hpp"
+#include "gc/g1/satbMarkQueue.hpp"
#endif // INCLUDE_ALL_GCS
#ifdef TARGET_ARCH_zero
# include "stack_zero.hpp"
@@ -992,7 +992,7 @@
#if INCLUDE_ALL_GCS
// Support for G1 barriers
- ObjPtrQueue _satb_mark_queue; // Thread-local log for SATB barrier.
+ SATBMarkQueue _satb_mark_queue; // Thread-local log for SATB barrier.
// Set of all such queues.
static SATBMarkQueueSet _satb_mark_queue_set;
@@ -1727,7 +1727,7 @@
#if INCLUDE_ALL_GCS
// SATB marking queue support
- ObjPtrQueue& satb_mark_queue() { return _satb_mark_queue; }
+ SATBMarkQueue& satb_mark_queue() { return _satb_mark_queue; }
static SATBMarkQueueSet& satb_mark_queue_set() {
return _satb_mark_queue_set;
}
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -1025,7 +1025,7 @@
nonstatic_field(JavaThread, _stack_size, size_t) \
nonstatic_field(JavaThread, _vframe_array_head, vframeArray*) \
nonstatic_field(JavaThread, _vframe_array_last, vframeArray*) \
- nonstatic_field(JavaThread, _satb_mark_queue, ObjPtrQueue) \
+ nonstatic_field(JavaThread, _satb_mark_queue, SATBMarkQueue) \
nonstatic_field(JavaThread, _dirty_card_queue, DirtyCardQueue) \
nonstatic_field(Thread, _resource_area, ResourceArea*) \
nonstatic_field(CompilerThread, _env, ciEnv*) \
@@ -1617,7 +1617,7 @@
declare_toplevel_type(MemRegion) \
declare_toplevel_type(ThreadLocalAllocBuffer) \
declare_toplevel_type(VirtualSpace) \
- declare_toplevel_type(ObjPtrQueue) \
+ declare_toplevel_type(SATBMarkQueue) \
declare_toplevel_type(DirtyCardQueue) \
\
/* Pointers to Garbage Collection types */ \
--- a/hotspot/src/share/vm/services/attachListener.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/services/attachListener.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -29,6 +29,7 @@
#include "utilities/debug.hpp"
#include "utilities/ostream.hpp"
#include "utilities/macros.hpp"
+#include "utilities/globalDefinitions.hpp"
// The AttachListener thread services a queue of operations that are enqueued
// by client tools. Each operation is identified by a name and has up to 3
@@ -121,8 +122,9 @@
// set the operation name
void set_name(char* name) {
- assert(strlen(name) <= name_length_max, "exceeds maximum name length");
- strcpy(_name, name);
+ size_t len = strlen(name);
+ assert(len <= name_length_max, "exceeds maximum name length");
+ memcpy(_name, name, MIN2(len + 1, (size_t)name_length_max));
}
// get an argument value
@@ -137,8 +139,9 @@
if (arg == NULL) {
_arg[i][0] = '\0';
} else {
- assert(strlen(arg) <= arg_length_max, "exceeds maximum argument length");
- strcpy(_arg[i], arg);
+ size_t len = strlen(arg);
+ assert(len <= arg_length_max, "exceeds maximum argument length");
+ memcpy(_arg[i], arg, MIN2(len + 1, (size_t)arg_length_max));
}
}
--- a/hotspot/src/share/vm/services/heapDumper.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/services/heapDumper.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -897,8 +897,10 @@
void DumperSupport::dump_class_and_array_classes(DumpWriter* writer, Klass* k) {
InstanceKlass* ik = InstanceKlass::cast(k);
- // Ignore the class if it hasn't been initialized yet
- if (!ik->is_linked()) {
+ // We can safepoint and do a heap dump at a point where we have a Klass,
+ // but no java mirror class has been setup for it. So we need to check
+ // that the class is at least loaded, to avoid crash from a null mirror.
+ if (!ik->is_loaded()) {
return;
}
@@ -1971,7 +1973,7 @@
if (HeapDumpPath == NULL || HeapDumpPath[0] == '\0') {
// HeapDumpPath=<file> not specified
} else {
- strncpy(base_path, HeapDumpPath, sizeof(base_path));
+ strcpy(base_path, HeapDumpPath);
// check if the path is a directory (must exist)
DIR* dir = os::opendir(base_path);
if (dir == NULL) {
--- a/hotspot/src/share/vm/services/memoryService.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/services/memoryService.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -546,7 +546,7 @@
CHECK_NH);
return obj;
}
-//
+
// GC manager type depends on the type of Generation. Depending on the space
// availability and vm options the gc uses major gc manager or minor gc
// manager or both. The type of gc manager depends on the generation kind.
@@ -559,21 +559,23 @@
#if INCLUDE_ALL_GCS
case Generation::ParNew:
#endif // INCLUDE_ALL_GCS
- _fullGC=false;
+ _fullGC = false;
break;
case Generation::MarkSweepCompact:
#if INCLUDE_ALL_GCS
case Generation::ConcurrentMarkSweep:
#endif // INCLUDE_ALL_GCS
- _fullGC=true;
+ _fullGC = true;
break;
default:
+ _fullGC = false;
assert(false, "Unrecognized gc generation kind.");
}
// this has to be called in a stop the world pause and represent
// an entire gc pause, start to finish:
- initialize(_fullGC, cause,true, true, true, true, true, true, true);
+ initialize(_fullGC, cause, true, true, true, true, true, true, true);
}
+
TraceMemoryManagerStats::TraceMemoryManagerStats(bool fullGC,
GCCause::Cause cause,
bool recordGCBeginTime,
@@ -583,7 +585,7 @@
bool recordAccumulatedGCTime,
bool recordGCEndTime,
bool countCollection) {
- initialize(fullGC, cause, recordGCBeginTime, recordPreGCUsage, recordPeakUsage,
+ initialize(fullGC, cause, recordGCBeginTime, recordPreGCUsage, recordPeakUsage,
recordPostGCUsage, recordAccumulatedGCTime, recordGCEndTime,
countCollection);
}
--- a/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -171,9 +171,11 @@
#define strdup _strdup
#endif
+#if _MSC_VER < 1800
// Visual Studio 2013 introduced strtoull(); before, one has to use _strtoui64() instead.
-#if _MSC_VER < 1800
#define strtoull _strtoui64
+// Fixes some wrong warnings about 'this' : used in base member initializer list
+#pragma warning( disable : 4355 )
#endif
--- a/hotspot/src/share/vm/utilities/ostream.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/utilities/ostream.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -1449,6 +1449,6 @@
_current_line.reset();
} else {
_current_line.write(s, len);
- update_position(s, len);
}
+ update_position(s, len);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/utilities/resourceHash.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "memory/allocation.hpp"
+#include "memory/resourceArea.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/resourceHash.hpp"
+
+#ifndef PRODUCT
+
+/////////////// Unit tests ///////////////
+
+class TestResourceHashtable : public AllStatic {
+ typedef void* K;
+ typedef int V;
+
+ static unsigned identity_hash(const K& k) {
+ return (unsigned)(uintptr_t)k;
+ }
+
+ static unsigned bad_hash(const K& k) {
+ return 1;
+ }
+
+ class EqualityTestIter {
+ public:
+ bool do_entry(K const& k, V const& v) {
+ assert((uintptr_t)k == (uintptr_t)v, "");
+ return true; // continue iteration
+ }
+ };
+
+ template<
+ unsigned (*HASH) (K const&) = primitive_hash<K>,
+ bool (*EQUALS)(K const&, K const&) = primitive_equals<K>,
+ unsigned SIZE = 256,
+ ResourceObj::allocation_type ALLOC_TYPE = ResourceObj::RESOURCE_AREA,
+ MEMFLAGS MEM_TYPE = mtInternal
+ >
+ class Runner : public AllStatic {
+ static void* as_K(uintptr_t val) { return (void*)val; }
+
+ public:
+ static void test_small() {
+ EqualityTestIter et;
+ ResourceHashtable<K, V, HASH, EQUALS, SIZE, ALLOC_TYPE, MEM_TYPE> rh;
+
+ assert(!rh.contains(as_K(0x1)), "");
+
+ assert(rh.put(as_K(0x1), 0x1), "");
+ assert(rh.contains(as_K(0x1)), "");
+
+ assert(!rh.put(as_K(0x1), 0x1), "");
+
+ assert(rh.put(as_K(0x2), 0x2), "");
+ assert(rh.put(as_K(0x3), 0x3), "");
+ assert(rh.put(as_K(0x4), 0x4), "");
+ assert(rh.put(as_K(0x5), 0x5), "");
+
+ assert(!rh.remove(as_K(0x0)), "");
+ rh.iterate(&et);
+
+ assert(rh.remove(as_K(0x1)), "");
+ rh.iterate(&et);
+
+ }
+
+ // We use keys with the low bits cleared since the default hash will do some shifting
+ static void test_small_shifted() {
+ EqualityTestIter et;
+ ResourceHashtable<K, V, HASH, EQUALS, SIZE, ALLOC_TYPE, MEM_TYPE> rh;
+
+ assert(!rh.contains(as_K(0x10)), "");
+
+ assert(rh.put(as_K(0x10), 0x10), "");
+ assert(rh.contains(as_K(0x10)), "");
+
+ assert(!rh.put(as_K(0x10), 0x10), "");
+
+ assert(rh.put(as_K(0x20), 0x20), "");
+ assert(rh.put(as_K(0x30), 0x30), "");
+ assert(rh.put(as_K(0x40), 0x40), "");
+ assert(rh.put(as_K(0x50), 0x50), "");
+
+ assert(!rh.remove(as_K(0x00)), "");
+
+ assert(rh.remove(as_K(0x10)), "");
+
+ rh.iterate(&et);
+ }
+
+ static void test(unsigned num_elements = SIZE) {
+ EqualityTestIter et;
+ ResourceHashtable<K, V, HASH, EQUALS, SIZE, ALLOC_TYPE, MEM_TYPE> rh;
+
+ for (uintptr_t i = 0; i < num_elements; ++i) {
+ assert(rh.put(as_K(i), i), "");
+ }
+
+ rh.iterate(&et);
+
+ for (uintptr_t i = num_elements; i > 0; --i) {
+ uintptr_t index = i - 1;
+ assert(rh.remove(as_K(index)), "");
+ }
+ rh.iterate(&et);
+ for (uintptr_t i = num_elements; i > 0; --i) {
+ uintptr_t index = i - 1;
+ assert(!rh.remove(as_K(index)), "");
+ }
+ rh.iterate(&et);
+ }
+ };
+
+ public:
+ static void run_tests() {
+ {
+ ResourceMark rm;
+ Runner<>::test_small();
+ Runner<>::test_small_shifted();
+ Runner<>::test();
+ }
+
+ {
+ ResourceMark rm;
+ Runner<identity_hash>::test_small();
+ Runner<identity_hash>::test_small_shifted();
+ Runner<identity_hash>::test();
+ }
+
+ {
+ ResourceMark rm;
+ Runner<bad_hash>::test_small();
+ Runner<bad_hash>::test_small_shifted();
+ Runner<bad_hash>::test();
+ }
+
+
+ assert(Thread::current()->resource_area()->nesting() == 0, "this code depends on not having an active ResourceMark");
+ // The following test calls will cause an assert if resource allocations occur since we don't have an active mark
+ Runner<primitive_hash<K>, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test_small();
+ Runner<primitive_hash<K>, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test_small_shifted();
+ Runner<primitive_hash<K>, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test();
+
+ Runner<bad_hash, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test_small();
+ Runner<bad_hash, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test_small_shifted();
+ Runner<bad_hash, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test();
+
+ Runner<identity_hash, primitive_equals<K>, 1, ResourceObj::C_HEAP>::test_small();
+ Runner<identity_hash, primitive_equals<K>, 1, ResourceObj::C_HEAP>::test_small_shifted();
+ Runner<identity_hash, primitive_equals<K>, 1, ResourceObj::C_HEAP>::test(512);
+ }
+};
+
+void TestResourcehash_test() {
+ TestResourceHashtable::run_tests();
+}
+
+#endif // not PRODUCT
+
--- a/hotspot/src/share/vm/utilities/resourceHash.hpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/utilities/resourceHash.hpp Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,7 @@
template<typename K> unsigned primitive_hash(const K& k) {
unsigned hash = (unsigned)((uintptr_t)k);
- return hash ^ (hash > 3); // just in case we're dealing with aligned ptrs
+ return hash ^ (hash >> 3); // just in case we're dealing with aligned ptrs
}
template<typename K> bool primitive_equals(const K& k0, const K& k1) {
@@ -50,7 +50,9 @@
//typename ResourceHashtableFns<K>::equals_fn EQUALS = primitive_equals<K>,
unsigned (*HASH) (K const&) = primitive_hash<K>,
bool (*EQUALS)(K const&, K const&) = primitive_equals<K>,
- unsigned SIZE = 256
+ unsigned SIZE = 256,
+ ResourceObj::allocation_type ALLOC_TYPE = ResourceObj::RESOURCE_AREA,
+ MEMFLAGS MEM_TYPE = mtInternal
>
class ResourceHashtable : public ResourceObj {
private:
@@ -91,6 +93,21 @@
public:
ResourceHashtable() { memset(_table, 0, SIZE * sizeof(Node*)); }
+ ~ResourceHashtable() {
+ if (ALLOC_TYPE == C_HEAP) {
+ Node* const* bucket = _table;
+ while (bucket < &_table[SIZE]) {
+ Node* node = *bucket;
+ while (node != NULL) {
+ Node* cur = node;
+ node = node->_next;
+ delete cur;
+ }
+ ++bucket;
+ }
+ }
+ }
+
bool contains(K const& key) const {
return get(key) != NULL;
}
@@ -117,11 +134,26 @@
(*ptr)->_value = value;
return false;
} else {
- *ptr = new Node(hv, key, value);
+ *ptr = new (ALLOC_TYPE, MEM_TYPE) Node(hv, key, value);
return true;
}
}
+ bool remove(K const& key) {
+ unsigned hv = HASH(key);
+ Node** ptr = lookup_node(hv, key);
+
+ Node* node = *ptr;
+ if (node != NULL) {
+ *ptr = node->_next;
+ if (ALLOC_TYPE == C_HEAP) {
+ delete node;
+ }
+ return true;
+ }
+ return false;
+ }
+
// ITER contains bool do_entry(K const&, V const&), which will be
// called for each entry in the table. If do_entry() returns false,
// the iteration is cancelled.
@@ -138,6 +170,10 @@
++bucket;
}
}
+
+ static size_t node_size() {
+ return sizeof(Node);
+ }
};
--- a/hotspot/src/share/vm/utilities/xmlstream.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/src/share/vm/utilities/xmlstream.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -346,13 +346,16 @@
// ------------------------------------------------------------------
void xmlStream::va_done(const char* format, va_list ap) {
char buffer[200];
- guarantee(strlen(format) + 10 < sizeof(buffer), "bigger format buffer");
+ size_t format_len = strlen(format);
+ guarantee(format_len + 10 < sizeof(buffer), "bigger format buffer");
const char* kind = format;
const char* kind_end = strchr(kind, ' ');
- size_t kind_len = (kind_end != NULL) ? (kind_end - kind) : strlen(kind);
+ size_t kind_len = (kind_end != NULL) ? (kind_end - kind) : format_len;
strncpy(buffer, kind, kind_len);
strcpy(buffer + kind_len, "_done");
- strcat(buffer, format + kind_len);
+ if (kind_end != NULL) {
+ strncat(buffer, format + kind_len, sizeof(buffer) - (kind_len + 5 /* _done */) - 1);
+ }
// Output the trailing event with the timestamp.
va_begin_elem(buffer, ap);
stamp();
--- a/hotspot/test/TEST.ROOT Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/TEST.ROOT Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -32,5 +32,9 @@
groups=TEST.groups [closed/TEST.groups]
requires.properties=sun.arch.data.model
-# Tests using jtreg 4.1 b11 features
-requiredVersion=4.1 b11
+# Tests using jtreg 4.1 b12 features
+requiredVersion=4.1 b12
+
+# Path to libraries in the topmost test directory. This is needed so @library
+# does not need ../../ notation to reach them
+external.lib.roots = ../../
--- a/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnSupportedCPU.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnSupportedCPU.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @bug 8031321
* @summary Verify processing of UseBMI1Instructions option on CPU with
* BMI1 feature support.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestUseBMI1InstructionsOnSupportedCPU
--- a/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnUnsupportedCPU.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnUnsupportedCPU.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @bug 8031321
* @summary Verify processing of UseBMI1Instructions option on CPU without
* BMI1 feature support.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestUseBMI1InstructionsOnUnsupportedCPU
--- a/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnSupportedCPU.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnSupportedCPU.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @bug 8031321
* @summary Verify processing of UseCountLeadingZerosInstruction option
* on CPU with LZCNT support.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestUseCountLeadingZerosInstructionOnSupportedCPU
--- a/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnUnsupportedCPU.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnUnsupportedCPU.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @bug 8031321
* @summary Verify processing of UseCountLeadingZerosInstruction option
* on CPU without LZCNT support.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestUseCountLeadingZerosInstructionOnUnsupportedCPU
--- a/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnSupportedCPU.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnSupportedCPU.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @bug 8031321
* @summary Verify processing of UseCountTrailingZerosInstruction option
* on CPU with TZCNT (BMI1 feature) support.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestUseCountTrailingZerosInstructionOnSupportedCPU
--- a/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnUnsupportedCPU.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnUnsupportedCPU.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @bug 8031321
* @summary Verify processing of UseCountTrailingZerosInstruction option
* on CPU without TZCNT instruction (BMI1 feature) support.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestUseCountTrailingZerosInstructionOnUnsupportedCPU
--- a/hotspot/test/compiler/arraycopy/TestArrayCopyNoInitDeopt.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/arraycopy/TestArrayCopyNoInitDeopt.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8072016
* @summary Infinite deoptimization/recompilation cycles in case of arraycopy with tightly coupled allocation
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* @modules java.base/sun.misc
* java.management
* @build TestArrayCopyNoInitDeopt
--- a/hotspot/test/compiler/c2/6589834/Test_ia32.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/c2/6589834/Test_ia32.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @bug 6589834
* @summary Safepoint placed between stack pointer increment and decrement leads
* to interpreter's stack corruption after deoptimization.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.compiler
* java.management
--- a/hotspot/test/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java Wed Jul 05 21:02:29 2017 +0200
@@ -33,7 +33,7 @@
* @test TestAnonymousClassUnloading
* @bug 8054402
* @summary "Tests unloading of anonymous classes."
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* @compile TestAnonymousClassUnloading.java
* @run main ClassFileInstaller TestAnonymousClassUnloading
--- a/hotspot/test/compiler/classUnloading/methodUnloading/TestMethodUnloading.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/classUnloading/methodUnloading/TestMethodUnloading.java Wed Jul 05 21:02:29 2017 +0200
@@ -31,7 +31,7 @@
* @test MethodUnloadingTest
* @bug 8029443
* @summary "Tests the unloading of methods to to class unloading"
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build TestMethodUnloading
* @build WorkerClass
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/codecache/CheckSegmentedCodeCache.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/CheckSegmentedCodeCache.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
/*
* @test CheckSegmentedCodeCache
* @bug 8015774
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @summary "Checks VM options related to the segmented code cache"
* @modules java.base/sun.misc
* java.management
--- a/hotspot/test/compiler/codecache/OverflowCodeCacheTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/OverflowCodeCacheTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -34,7 +34,7 @@
/*
* @test OverflowCodeCacheTest
* @bug 8059550
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build OverflowCodeCacheTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/codecache/cli/TestSegmentedCodeCacheOption.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/cli/TestSegmentedCodeCacheOption.java Wed Jul 05 21:02:29 2017 +0200
@@ -30,7 +30,7 @@
* @test
* @bug 8015774
* @summary Verify SegmentedCodeCache option's processing
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.compiler
* java.management
--- a/hotspot/test/compiler/codecache/cli/codeheapsize/TestCodeHeapSizeOptions.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/cli/codeheapsize/TestCodeHeapSizeOptions.java Wed Jul 05 21:02:29 2017 +0200
@@ -31,7 +31,7 @@
* @test
* @bug 8015774
* @summary Verify processing of options related to code heaps sizing.
- * @library /testlibrary .. /../../test/lib
+ * @library /testlibrary .. /test/lib
* @modules java.base/sun.misc
* java.compiler
* java.management
--- a/hotspot/test/compiler/codecache/cli/printcodecache/TestPrintCodeCacheOption.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/cli/printcodecache/TestPrintCodeCacheOption.java Wed Jul 05 21:02:29 2017 +0200
@@ -30,7 +30,7 @@
* @test
* @bug 8015774
* @summary Verify that PrintCodeCache option print correct information.
- * @library /testlibrary .. /../../test/lib
+ * @library /testlibrary .. /test/lib
* @modules java.base/sun.misc
* java.compiler
* java.management
--- a/hotspot/test/compiler/codecache/dtrace/SegmentedCodeCacheDtraceTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/dtrace/SegmentedCodeCacheDtraceTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -48,7 +48,7 @@
* @test SegmentedCodeCacheDtraceTest
* @bug 8015774
* @requires os.family=="solaris"
- * @library /testlibrary / /../../test/lib
+ * @library /testlibrary / /test/lib
* @build SegmentedCodeCacheDtraceTestWorker
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
--- a/hotspot/test/compiler/codecache/jmx/BeanTypeTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/jmx/BeanTypeTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
/**
* @test BeanTypeTest
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build BeanTypeTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/codecache/jmx/CodeHeapBeanPresenceTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/jmx/CodeHeapBeanPresenceTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
/**
* @test CodeHeapBeanPresenceTest
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build CodeHeapBeanPresenceTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/codecache/jmx/GetUsageTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/jmx/GetUsageTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -29,7 +29,7 @@
/*
* @test GetUsageTest
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build GetUsageTest
--- a/hotspot/test/compiler/codecache/jmx/InitialAndMaxUsageTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/jmx/InitialAndMaxUsageTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -29,7 +29,7 @@
/*
* @test InitialAndMaxUsageTest
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build InitialAndMaxUsageTest
--- a/hotspot/test/compiler/codecache/jmx/ManagerNamesTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/jmx/ManagerNamesTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
/**
* @test ManagerNamesTest
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build ManagerNamesTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/codecache/jmx/MemoryPoolsPresenceTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/jmx/MemoryPoolsPresenceTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -32,7 +32,7 @@
/**
* @test MemoryPoolsPresenceTest
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build MemoryPoolsPresenceTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/codecache/jmx/PeakUsageTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/jmx/PeakUsageTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
/*
* @test PeakUsageTest
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build PeakUsageTest
--- a/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -37,7 +37,7 @@
/*
* @test PoolsIndependenceTest
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build PoolsIndependenceTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
--- a/hotspot/test/compiler/codecache/jmx/ThresholdNotificationsTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/jmx/ThresholdNotificationsTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -34,7 +34,7 @@
/*
* @test ThresholdNotificationsTest
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build ThresholdNotificationsTest
--- a/hotspot/test/compiler/codecache/jmx/UsageThresholdExceededSeveralTimesTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/jmx/UsageThresholdExceededSeveralTimesTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test UsageThresholdExceededSeveralTimesTest
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build UsageThresholdExceededTest
--- a/hotspot/test/compiler/codecache/jmx/UsageThresholdExceededTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/jmx/UsageThresholdExceededTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
/*
* @test UsageThresholdExceededTest
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build UsageThresholdExceededTest
--- a/hotspot/test/compiler/codecache/jmx/UsageThresholdIncreasedTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/jmx/UsageThresholdIncreasedTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
/*
* @test UsageThresholdIncreasedTest
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build UsageThresholdIncreasedTest
--- a/hotspot/test/compiler/codecache/jmx/UsageThresholdNotExceededTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/jmx/UsageThresholdNotExceededTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
/*
* @test UsageThresholdNotExceededTest
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build UsageThresholdNotExceededTest
--- a/hotspot/test/compiler/codecache/stress/OverloadCompileQueueTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/stress/OverloadCompileQueueTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -29,7 +29,7 @@
/*
* @test OverloadCompileQueueTest
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @ignore 8071905
--- a/hotspot/test/compiler/codecache/stress/RandomAllocationTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/stress/RandomAllocationTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -28,7 +28,7 @@
/*
* @test RandomAllocationTest
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build RandomAllocationTest
--- a/hotspot/test/compiler/codecache/stress/UnexpectedDeoptimizationTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/codecache/stress/UnexpectedDeoptimizationTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test UnexpectedDeoptimizationTest
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build UnexpectedDeoptimizationTest
--- a/hotspot/test/compiler/compilercontrol/matcher/MethodMatcherTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/compilercontrol/matcher/MethodMatcherTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -40,7 +40,7 @@
* @test
* @bug 8135068
* @summary Tests CompilerCommand's method matcher
- * @library /testlibrary /../../test/lib /compiler/whitebox ../share /
+ * @library /testlibrary /test/lib /compiler/whitebox ../share /
* @build MethodMatcherTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
--- a/hotspot/test/compiler/floatingpoint/TestPow2.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/floatingpoint/TestPow2.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8063086
* @summary X^2 special case for C2 yields different result than interpreter
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* @modules java.management
* @build TestPow2
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/intrinsics/IntrinsicAvailableTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/IntrinsicAvailableTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
/*
* @test
* @bug 8130832
- * @library /testlibrary /../../test/lib /compiler/whitebox /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/whitebox /compiler/testlibrary
* @build IntrinsicAvailableTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
--- a/hotspot/test/compiler/intrinsics/bmi/TestAndnI.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/TestAndnI.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031321
* @summary Verify that results of computations are the same w/
* and w/o usage of ANDN instruction
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestAndnI BMITestRunner Expr
--- a/hotspot/test/compiler/intrinsics/bmi/TestAndnL.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/TestAndnL.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031321
* @summary Verify that results of computations are the same w/
* and w/o usage of ANDN instruction
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestAndnL BMITestRunner Expr
--- a/hotspot/test/compiler/intrinsics/bmi/TestBlsiI.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsiI.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031321
* @summary Verify that results of computations are the same w/
* and w/o usage of BLSI instruction
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestBlsiI BMITestRunner Expr
--- a/hotspot/test/compiler/intrinsics/bmi/TestBlsiL.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsiL.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031321
* @summary Verify that results of computations are the same w/
* and w/o usage of BLSI instruction
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestBlsiL BMITestRunner Expr
--- a/hotspot/test/compiler/intrinsics/bmi/TestBlsmskI.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsmskI.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031321
* @summary Verify that results of computations are the same w/
* and w/o usage of BLSMSK instruction
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestBlsmskI BMITestRunner Expr
--- a/hotspot/test/compiler/intrinsics/bmi/TestBlsmskL.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsmskL.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031321
* @summary Verify that results of computations are the same w/
* and w/o usage of BLSMSK instruction
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestBlsmskL BMITestRunner Expr
--- a/hotspot/test/compiler/intrinsics/bmi/TestBlsrI.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsrI.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031321
* @summary Verify that results of computations are the same w/
* and w/o usage of BLSR instruction
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestBlsrI BMITestRunner Expr
--- a/hotspot/test/compiler/intrinsics/bmi/TestBlsrL.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsrL.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031321
* @summary Verify that results of computations are the same w/
* and w/o usage of BLSR instruction
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestBlsrL BMITestRunner Expr
--- a/hotspot/test/compiler/intrinsics/bmi/TestLzcntI.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/TestLzcntI.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031321
* @summary Verify that results of computations are the same w/
* and w/o usage of intrinsic
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestLzcntI BMITestRunner Expr
--- a/hotspot/test/compiler/intrinsics/bmi/TestLzcntL.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/TestLzcntL.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031321
* @summary Verify that results of computations are the same w/
* and w/o usage of intrinsic
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestLzcntL BMITestRunner Expr
--- a/hotspot/test/compiler/intrinsics/bmi/TestTzcntI.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/TestTzcntI.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031321
* @summary Verify that results of computations are the same w/
* and w/o usage of intrinsic
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestTzcntI BMITestRunner Expr
--- a/hotspot/test/compiler/intrinsics/bmi/TestTzcntL.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/TestTzcntL.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031321
* @summary Verify that results of computations are the same w/
* and w/o usage of intrinsic
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestTzcntL BMITestRunner Expr
--- a/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestI.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestI.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8031321
- * @library /testlibrary /../../test/lib /compiler/whitebox ..
+ * @library /testlibrary /test/lib /compiler/whitebox ..
* @modules java.base/sun.misc
* java.management
* @build AddnTestI
--- a/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestL.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestL.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8031321
- * @library /testlibrary /../../test/lib /compiler/whitebox ..
+ * @library /testlibrary /test/lib /compiler/whitebox ..
* @modules java.base/sun.misc
* java.management
* @build AddnTestL
--- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestI.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestI.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8031321
- * @library /testlibrary /../../test/lib /compiler/whitebox ..
+ * @library /testlibrary /test/lib /compiler/whitebox ..
* @modules java.base/sun.misc
* java.management
* @build BlsiTestI
--- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestL.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestL.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8031321
- * @library /testlibrary /../../test/lib /compiler/whitebox ..
+ * @library /testlibrary /test/lib /compiler/whitebox ..
* @modules java.base/sun.misc
* java.management
* @build BlsiTestL
--- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestI.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestI.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8031321
- * @library /testlibrary /../../test/lib /compiler/whitebox ..
+ * @library /testlibrary /test/lib /compiler/whitebox ..
* @modules java.base/sun.misc
* java.management
* @build BlsmskTestI
--- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestL.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestL.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8031321
- * @library /testlibrary /../../test/lib /compiler/whitebox ..
+ * @library /testlibrary /test/lib /compiler/whitebox ..
* @modules java.base/sun.misc
* java.management
* @build BlsmskTestL
--- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestI.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestI.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8031321
- * @library /testlibrary /../../test/lib /compiler/whitebox ..
+ * @library /testlibrary /test/lib /compiler/whitebox ..
* @modules java.base/sun.misc
* java.management
* @build BlsrTestI
--- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestL.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestL.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8031321
- * @library /testlibrary /../../test/lib /compiler/whitebox ..
+ * @library /testlibrary /test/lib /compiler/whitebox ..
* @modules java.base/sun.misc
* java.management
* @build BlsrTestL
--- a/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestI.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestI.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8031321
- * @library /testlibrary /../../test/lib /compiler/whitebox ..
+ * @library /testlibrary /test/lib /compiler/whitebox ..
* @modules java.base/sun.misc
* java.management
* @build LZcntTestI
--- a/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestL.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestL.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8031321
- * @library /testlibrary /../../test/lib /compiler/whitebox ..
+ * @library /testlibrary /test/lib /compiler/whitebox ..
* @modules java.base/sun.misc
* java.management
* @build LZcntTestL
--- a/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestI.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestI.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8031321
- * @library /testlibrary /../../test/lib /compiler/whitebox ..
+ * @library /testlibrary /test/lib /compiler/whitebox ..
* @modules java.base/sun.misc
* java.management
* @build TZcntTestI
--- a/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestL.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestL.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8031321
- * @library /testlibrary /../../test/lib /compiler/whitebox ..
+ * @library /testlibrary /test/lib /compiler/whitebox ..
* @modules java.base/sun.misc
* java.management
* @build TZcntTestL
--- a/hotspot/test/compiler/intrinsics/classcast/NullCheckDroppingsTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/classcast/NullCheckDroppingsTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test NullCheckDroppingsTest
* @bug 8054492
* @summary "Casting can result in redundant null checks in generated code"
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build ClassFileInstaller sun.hotspot.WhiteBox jdk.test.lib.*
--- a/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
--- a/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
--- a/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
--- a/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
--- a/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
--- a/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
--- a/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
--- a/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
--- a/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
--- a/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
--- a/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
--- a/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
--- a/hotspot/test/compiler/intrinsics/sha/cli/TestUseSHA1IntrinsicsOptionOnSupportedCPU.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/sha/cli/TestUseSHA1IntrinsicsOptionOnSupportedCPU.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8035968
* @summary Verify UseSHA1Intrinsics option processing on supported CPU,
- * @library /testlibrary /../../test/lib /compiler/testlibrary testcases
+ * @library /testlibrary /test/lib /compiler/testlibrary testcases
* @modules java.base/sun.misc
* java.management
* @build TestUseSHA1IntrinsicsOptionOnSupportedCPU
--- a/hotspot/test/compiler/intrinsics/sha/cli/TestUseSHA1IntrinsicsOptionOnUnsupportedCPU.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/sha/cli/TestUseSHA1IntrinsicsOptionOnUnsupportedCPU.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8035968
* @summary Verify UseSHA1Intrinsics option processing on unsupported CPU,
- * @library /testlibrary /../../test/lib /compiler/testlibrary testcases
+ * @library /testlibrary /test/lib /compiler/testlibrary testcases
* @modules java.base/sun.misc
* java.management
* @build TestUseSHA1IntrinsicsOptionOnUnsupportedCPU
--- a/hotspot/test/compiler/intrinsics/sha/cli/TestUseSHA256IntrinsicsOptionOnSupportedCPU.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/sha/cli/TestUseSHA256IntrinsicsOptionOnSupportedCPU.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8035968
* @summary Verify UseSHA256Intrinsics option processing on supported CPU,
- * @library /testlibrary /../../test/lib /compiler/testlibrary testcases
+ * @library /testlibrary /test/lib /compiler/testlibrary testcases
* @modules java.base/sun.misc
* java.management
* @build TestUseSHA256IntrinsicsOptionOnSupportedCPU
--- a/hotspot/test/compiler/intrinsics/sha/cli/TestUseSHA256IntrinsicsOptionOnUnsupportedCPU.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/sha/cli/TestUseSHA256IntrinsicsOptionOnUnsupportedCPU.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8035968
* @summary Verify UseSHA256Intrinsics option processing on unsupported CPU,
- * @library /testlibrary /../../test/lib /compiler/testlibrary testcases
+ * @library /testlibrary /test/lib /compiler/testlibrary testcases
* @modules java.base/sun.misc
* java.management
* @build TestUseSHA256IntrinsicsOptionOnUnsupportedCPU
--- a/hotspot/test/compiler/intrinsics/sha/cli/TestUseSHA512IntrinsicsOptionOnSupportedCPU.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/sha/cli/TestUseSHA512IntrinsicsOptionOnSupportedCPU.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8035968
* @summary Verify UseSHA512Intrinsics option processing on supported CPU.
- * @library /testlibrary /../../test/lib /compiler/testlibrary testcases
+ * @library /testlibrary /test/lib /compiler/testlibrary testcases
* @modules java.base/sun.misc
* java.management
* @build TestUseSHA512IntrinsicsOptionOnSupportedCPU
--- a/hotspot/test/compiler/intrinsics/sha/cli/TestUseSHA512IntrinsicsOptionOnUnsupportedCPU.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/sha/cli/TestUseSHA512IntrinsicsOptionOnUnsupportedCPU.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8035968
* @summary Verify UseSHA512Intrinsics option processing on unsupported CPU,
- * @library /testlibrary /../../test/lib /compiler/testlibrary testcases
+ * @library /testlibrary /test/lib /compiler/testlibrary testcases
* @modules java.base/sun.misc
* java.management
* @build TestUseSHA512IntrinsicsOptionOnUnsupportedCPU
--- a/hotspot/test/compiler/intrinsics/sha/cli/TestUseSHAOptionOnSupportedCPU.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/sha/cli/TestUseSHAOptionOnSupportedCPU.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8035968
* @summary Verify UseSHA option processing on supported CPU,
- * @library /testlibrary /../../test/lib /compiler/testlibrary testcases
+ * @library /testlibrary /test/lib /compiler/testlibrary testcases
* @modules java.base/sun.misc
* java.management
* @build TestUseSHAOptionOnSupportedCPU
--- a/hotspot/test/compiler/intrinsics/sha/cli/TestUseSHAOptionOnUnsupportedCPU.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/sha/cli/TestUseSHAOptionOnUnsupportedCPU.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8035968
* @summary Verify UseSHA option processing on unsupported CPU.
- * @library /testlibrary /../../test/lib /compiler/testlibrary testcases
+ * @library /testlibrary /test/lib /compiler/testlibrary testcases
* @modules java.base/sun.misc
* java.management
* @build TestUseSHAOptionOnUnsupportedCPU
--- a/hotspot/test/compiler/intrinsics/sha/sanity/TestSHA1Intrinsics.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/sha/sanity/TestSHA1Intrinsics.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8035968
* @summary Verify that SHA-1 intrinsic is actually used.
- * @library /testlibrary /../../test/lib /compiler/testlibrary ../
+ * @library /testlibrary /test/lib /compiler/testlibrary ../
* @modules java.base/sun.misc
* java.management
* @build TestSHA intrinsics.Verifier TestSHA1Intrinsics
--- a/hotspot/test/compiler/intrinsics/sha/sanity/TestSHA1MultiBlockIntrinsics.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/sha/sanity/TestSHA1MultiBlockIntrinsics.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @test
* @bug 8035968
* @summary Verify that SHA-1 multi block intrinsic is actually used.
- * @library /testlibrary /../../test/lib /compiler/testlibrary ../
+ * @library /testlibrary /test/lib /compiler/testlibrary ../
* @modules java.base/sun.misc
* java.management
* @build TestSHA intrinsics.Verifier TestSHA1MultiBlockIntrinsics
--- a/hotspot/test/compiler/intrinsics/sha/sanity/TestSHA256Intrinsics.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/sha/sanity/TestSHA256Intrinsics.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @test
* @bug 8035968
* @summary Verify that SHA-256 intrinsic is actually used.
- * @library /testlibrary /../../test/lib /compiler/testlibrary ../
+ * @library /testlibrary /test/lib /compiler/testlibrary ../
* @modules java.base/sun.misc
* java.management
* @build TestSHA intrinsics.Verifier TestSHA256Intrinsics
--- a/hotspot/test/compiler/intrinsics/sha/sanity/TestSHA256MultiBlockIntrinsics.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/sha/sanity/TestSHA256MultiBlockIntrinsics.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @test
* @bug 8035968
* @summary Verify that SHA-256 multi block intrinsic is actually used.
- * @library /testlibrary /../../test/lib /compiler/testlibrary ../
+ * @library /testlibrary /test/lib /compiler/testlibrary ../
* @modules java.base/sun.misc
* java.management
* @build TestSHA intrinsics.Verifier TestSHA256MultiBlockIntrinsics
--- a/hotspot/test/compiler/intrinsics/sha/sanity/TestSHA512Intrinsics.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/sha/sanity/TestSHA512Intrinsics.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @test
* @bug 8035968
* @summary Verify that SHA-512 intrinsic is actually used.
- * @library /testlibrary /../../test/lib /compiler/testlibrary ../
+ * @library /testlibrary /test/lib /compiler/testlibrary ../
* @modules java.base/sun.misc
* java.management
* @build TestSHA intrinsics.Verifier TestSHA512Intrinsics
--- a/hotspot/test/compiler/intrinsics/sha/sanity/TestSHA512MultiBlockIntrinsics.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/intrinsics/sha/sanity/TestSHA512MultiBlockIntrinsics.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @test
* @bug 8035968
* @summary Verify that SHA-512 multi block intrinsic is actually used.
- * @library /testlibrary /../../test/lib /compiler/testlibrary ../
+ * @library /testlibrary /test/lib /compiler/testlibrary ../
* @modules java.base/sun.misc
* java.management
* @build TestSHA intrinsics.Verifier TestSHA512MultiBlockIntrinsics
--- a/hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @compile ./common/CompilerToVMHelper.java
* @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper
* @run main/othervm -XX:+UnlockExperimentalVMOptions -Xbootclasspath/a:.
--- a/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @compile ../common/CompilerToVMHelper.java
* @build sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @compile ../common/CompilerToVMHelper.java
* @build sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library / /testlibrary /../../test/lib/
+ * @library / /testlibrary /test/lib/
* @compile ../common/CompilerToVMHelper.java
* @run main ClassFileInstaller
* jdk.vm.ci.hotspot.CompilerToVMHelper
--- a/hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library / /testlibrary /../../test/lib
+ * @library / /testlibrary /test/lib
* @compile ../common/CompilerToVMHelper.java
* @run main ClassFileInstaller
* jdk.vm.ci.hotspot.CompilerToVMHelper
--- a/hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @ignore 8139700
* @compile ../common/CompilerToVMHelper.java
* @build sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @compile ../common/CompilerToVMHelper.java
* @build sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -22,7 +22,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @compile ../common/CompilerToVMHelper.java
* @build sun.hotspot.WhiteBox
* compiler.jvmci.compilerToVM.ExecuteInstalledCodeTest
--- a/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library / /testlibrary /../../test/lib
+ * @library / /testlibrary /test/lib
* @compile ../common/CompilerToVMHelper.java
* @build compiler.jvmci.compilerToVM.FindUniqueConcreteMethodTest
* @run main ClassFileInstaller
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @compile ../common/CompilerToVMHelper.java
* @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library / /testlibrary /../../test/lib
+ * @library / /testlibrary /test/lib
* @compile ../common/CompilerToVMHelper.java
* @build compiler.jvmci.compilerToVM.GetClassInitializerTest
* @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @compile ../common/CompilerToVMHelper.java ../common/PublicMetaspaceWrapperObject.java
* @build sun.hotspot.WhiteBox
* compiler.jvmci.compilerToVM.GetConstantPoolTest
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @compile ../common/CompilerToVMHelper.java
* @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library / /testlibrary /../../test/lib/
+ * @library / /testlibrary /test/lib/
* @compile ../common/CompilerToVMHelper.java
* @build compiler.jvmci.compilerToVM.GetImplementorTest
* @run main ClassFileInstaller
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @compile ../common/CompilerToVMHelper.java
* @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @clean compiler.jvmci.compilerToVM.*
* @compile -g DummyInterface.java
* @compile -g DummyAbstractClass.java
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library / /testlibrary /../../test/lib/
+ * @library / /testlibrary /test/lib/
* @compile ../common/CompilerToVMHelper.java
* @build compiler.jvmci.compilerToVM.GetMaxCallTargetOffsetTest
* @run main ClassFileInstaller
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library / /testlibrary /../../test/lib
+ * @library / /testlibrary /test/lib
* @compile ../common/CompilerToVMHelper.java
* @run main ClassFileInstaller
* jdk.vm.ci.hotspot.CompilerToVMHelper
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodAtSlotTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodAtSlotTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @compile ../common/CompilerToVMHelper.java
* @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library / /testlibrary /../../test/lib
+ * @library / /testlibrary /test/lib
* @compile ../common/CompilerToVMHelper.java
* ../common/PublicMetaspaceWrapperObject.java
* @build compiler.jvmci.compilerToVM.GetResolvedJavaMethodTest
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library / /testlibrary /../../test/lib
+ * @library / /testlibrary /test/lib
* @compile ../common/CompilerToVMHelper.java
* ../common/PublicMetaspaceWrapperObject.java
* @build compiler.jvmci.compilerToVM.GetResolvedJavaTypeTest
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @compile ../common/CompilerToVMHelper.java
* @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library / /testlibrary /../../test/lib
+ * @library / /testlibrary /test/lib
* @compile ../common/CompilerToVMHelper.java
* @build compiler.jvmci.compilerToVM.GetSymbolTest
* @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper
--- a/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library / /testlibrary /../../test/lib
+ * @library / /testlibrary /test/lib
* @compile ../common/CompilerToVMHelper.java
* @build compiler.jvmci.compilerToVM.GetVtableIndexForInterfaceTest
* @run main ClassFileInstaller
--- a/hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @compile ../common/CompilerToVMHelper.java
* @build sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library / /testlibrary /../../test/lib
+ * @library / /testlibrary /test/lib
* @compile ../common/CompilerToVMHelper.java
* @build compiler.jvmci.compilerToVM.HasFinalizableSubclassTest
* @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper
--- a/hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @ignore 8139700
* @compile ../common/CompilerToVMHelper.java
* @build sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library / /testlibrary /../../test/lib
+ * @library / /testlibrary /test/lib
* @compile ../common/CompilerToVMHelper.java
* @build sun.hotspot.WhiteBox IsMatureTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
* @summary Testing compiler.jvmci.CompilerToVM.lookupKlassInPool method
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @compile ../common/CompilerToVMHelper.java
* @build compiler.jvmci.common.testcases.MultipleImplementersInterface
* compiler.jvmci.common.testcases.MultipleImplementer2
--- a/hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library / /testlibrary /../../test/lib
+ * @library / /testlibrary /test/lib
* @ignore 8139703
* @compile ../common/CompilerToVMHelper.java
* @build sun.hotspot.WhiteBox MaterializeVirtualObjectTest
--- a/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @compile ../common/CompilerToVMHelper.java
* @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI
--- a/hotspot/test/compiler/jvmci/compilerToVM/ReadUncompressedOopTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ReadUncompressedOopTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library / /testlibrary /../../test/lib/
+ * @library / /testlibrary /test/lib/
* @compile ../common/CompilerToVMHelper.java
* @build compiler.jvmci.compilerToVM.ReadUncompressedOopTest
* @run main ClassFileInstaller
--- a/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @compile ../common/CompilerToVMHelper.java
* @build sun.hotspot.WhiteBox
* @run main ClassFileInstaller
--- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @compile ../common/CompilerToVMHelper.java
* @build compiler.jvmci.compilerToVM.ResolveConstantInPoolTest
* @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper
--- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library / /testlibrary /../../test/lib
+ * @library / /testlibrary /test/lib
* @compile ../common/CompilerToVMHelper.java
* @build compiler.jvmci.compilerToVM.ResolveMethodTest
* @run main ClassFileInstaller
--- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
* @summary Testing compiler.jvmci.CompilerToVM.resolveTypeInPool method
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @compile ../common/CompilerToVMHelper.java
* @build compiler.jvmci.common.testcases.MultipleImplementersInterface
* compiler.jvmci.common.testcases.MultipleImplementer2
--- a/hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library / /testlibrary /../../test/lib/
+ * @library / /testlibrary /test/lib/
* @compile ../common/CompilerToVMHelper.java
* @build compiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest
* @run main ClassFileInstaller
--- a/hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8136421
* @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64"
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @compile ../common/CompilerToVMHelper.java
* @build sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/oracle/GetMethodOptionTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/oracle/GetMethodOptionTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -30,7 +30,7 @@
/*
* @test
* @bug 8074980
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build sun.hotspot.WhiteBox jdk.test.lib.Asserts GetMethodOptionTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
--- a/hotspot/test/compiler/oracle/MethodMatcherTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/oracle/MethodMatcherTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -23,7 +23,8 @@
/*
* @test MethodMatcherTest
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
+ * @build sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI MethodMatcherTest
--- a/hotspot/test/compiler/rangechecks/TestExplicitRangeChecks.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rangechecks/TestExplicitRangeChecks.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8073480
* @summary explicit range checks should be recognized by C2
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* @build TestExplicitRangeChecks
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* @run main ClassFileInstaller jdk.test.lib.Platform
--- a/hotspot/test/compiler/rangechecks/TestRangeCheckSmearing.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rangechecks/TestRangeCheckSmearing.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8066103
* @summary C2's range check smearing allows out of bound array accesses
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* @modules java.base/sun.misc
* java.management
* @build TestRangeCheckSmearing
--- a/hotspot/test/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnSupportedConfig.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnSupportedConfig.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify PrintPreciseRTMLockingStatistics on CPUs with
* rtm support and on VM with rtm locking support,
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestPrintPreciseRTMLockingStatisticsOptionOnSupportedConfig
--- a/hotspot/test/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnUnsupportedConfig.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnUnsupportedConfig.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify PrintPreciseRTMLockingStatistics on CPUs without
* rtm support and/or unsupported VM.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestPrintPreciseRTMLockingStatisticsOptionOnUnsupportedConfig
--- a/hotspot/test/compiler/rtm/cli/TestRTMAbortRatioOptionOnSupportedConfig.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/cli/TestRTMAbortRatioOptionOnSupportedConfig.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify RTMAbortRatio option processing on CPU with rtm
* support and on VM with rtm locking support.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestRTMAbortRatioOptionOnSupportedConfig
--- a/hotspot/test/compiler/rtm/cli/TestRTMAbortRatioOptionOnUnsupportedConfig.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/cli/TestRTMAbortRatioOptionOnUnsupportedConfig.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify RTMAbortRatio option processing on CPU without rtm
* support or on VM that does not support rtm locking.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestRTMAbortRatioOptionOnUnsupportedConfig
--- a/hotspot/test/compiler/rtm/cli/TestRTMTotalCountIncrRateOptionOnSupportedConfig.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/cli/TestRTMTotalCountIncrRateOptionOnSupportedConfig.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify RTMTotalCountIncrRate option processing on CPU with
* rtm support and on VM with rtm locking support.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestRTMTotalCountIncrRateOptionOnSupportedConfig
--- a/hotspot/test/compiler/rtm/cli/TestRTMTotalCountIncrRateOptionOnUnsupportedConfig.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/cli/TestRTMTotalCountIncrRateOptionOnUnsupportedConfig.java Wed Jul 05 21:02:29 2017 +0200
@@ -32,7 +32,7 @@
* @bug 8031320
* @summary Verify RTMTotalCountIncrRate option processing on CPU without
* rtm support and/or on VM without rtm locking support.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestRTMTotalCountIncrRateOptionOnUnsupportedConfig
--- a/hotspot/test/compiler/rtm/cli/TestUseRTMDeoptOptionOnSupportedConfig.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/cli/TestUseRTMDeoptOptionOnSupportedConfig.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify UseRTMDeopt option processing on CPUs with rtm support
* when rtm locking is supported by VM.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestUseRTMDeoptOptionOnSupportedConfig
--- a/hotspot/test/compiler/rtm/cli/TestUseRTMDeoptOptionOnUnsupportedConfig.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/cli/TestUseRTMDeoptOptionOnUnsupportedConfig.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify UseRTMDeopt option processing on CPUs without rtm support
* or on VMs without rtm locking support.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestUseRTMDeoptOptionOnUnsupportedConfig
--- a/hotspot/test/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnSupportedConfig.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnSupportedConfig.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify UseRTMForStackLocks option processing on CPU with
* rtm support when VM supports rtm locking.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestUseRTMForStackLocksOptionOnSupportedConfig
--- a/hotspot/test/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnUnsupportedConfig.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnUnsupportedConfig.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify UseRTMForStackLocks option processing on CPUs without
* rtm support and/or on VMs without rtm locking support.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestUseRTMForStackLocksOptionOnUnsupportedConfig
--- a/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnSupportedConfig.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnSupportedConfig.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify UseRTMLocking option processing on CPU with rtm support and
* on VM with rtm-locking support.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestUseRTMLockingOptionOnSupportedConfig
--- a/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnUnsupportedCPU.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnUnsupportedCPU.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify UseRTMLocking option processing on CPU without
* rtm support.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestUseRTMLockingOptionOnUnsupportedCPU
--- a/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnUnsupportedVM.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionOnUnsupportedVM.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify UseRTMLocking option processing on CPU with rtm support
* in case when VM should not support this option.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestUseRTMLockingOptionOnUnsupportedVM
--- a/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionWithBiasedLocking.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/cli/TestUseRTMLockingOptionWithBiasedLocking.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify processing of UseRTMLocking and UseBiasedLocking
* options combination on CPU and VM with rtm support.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestUseRTMLockingOptionWithBiasedLocking
--- a/hotspot/test/compiler/rtm/locking/TestRTMAbortRatio.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestRTMAbortRatio.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify that RTMAbortRatio affects amount of aborts before
* deoptimization.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestRTMAbortRatio
--- a/hotspot/test/compiler/rtm/locking/TestRTMAbortThreshold.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestRTMAbortThreshold.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify that RTMAbortThreshold option affects
* amount of aborts after which abort ratio is calculated.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestRTMAbortThreshold
--- a/hotspot/test/compiler/rtm/locking/TestRTMAfterNonRTMDeopt.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestRTMAfterNonRTMDeopt.java Wed Jul 05 21:02:29 2017 +0200
@@ -29,7 +29,7 @@
* caused by reason other then rtm_state_change will reset
* method's RTM state. And if we don't use RTMDeopt, then
* RTM state remain the same after such deoptimization.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestRTMAfterNonRTMDeopt
--- a/hotspot/test/compiler/rtm/locking/TestRTMDeoptOnHighAbortRatio.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestRTMDeoptOnHighAbortRatio.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify that on high abort ratio method will be recompiled
* without rtm locking.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestRTMDeoptOnHighAbortRatio
--- a/hotspot/test/compiler/rtm/locking/TestRTMDeoptOnLowAbortRatio.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestRTMDeoptOnLowAbortRatio.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8031320
* @summary Verify that on low abort ratio method will be recompiled.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestRTMDeoptOnLowAbortRatio
--- a/hotspot/test/compiler/rtm/locking/TestRTMLockingCalculationDelay.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestRTMLockingCalculationDelay.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify that RTMLockingCalculationDelay affect when
* abort ratio calculation is started.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestRTMLockingCalculationDelay
--- a/hotspot/test/compiler/rtm/locking/TestRTMLockingThreshold.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestRTMLockingThreshold.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify that RTMLockingThreshold affects rtm state transition
* ProfileRTM => UseRTM.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestRTMLockingThreshold
--- a/hotspot/test/compiler/rtm/locking/TestRTMRetryCount.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestRTMRetryCount.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8031320
* @summary Verify that RTMRetryCount affects actual amount of retries.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestRTMRetryCount
--- a/hotspot/test/compiler/rtm/locking/TestRTMSpinLoopCount.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestRTMSpinLoopCount.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify that RTMSpinLoopCount affects time spent
* between locking attempts.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestRTMSpinLoopCount
--- a/hotspot/test/compiler/rtm/locking/TestRTMTotalCountIncrRate.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestRTMTotalCountIncrRate.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify that RTMTotalCountIncrRate option affects
* RTM locking statistics.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestRTMTotalCountIncrRate
--- a/hotspot/test/compiler/rtm/locking/TestUseRTMAfterLockInflation.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestUseRTMAfterLockInflation.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify that rtm locking is used for stack locks before
* inflation and after it used for inflated locks.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestUseRTMAfterLockInflation
--- a/hotspot/test/compiler/rtm/locking/TestUseRTMDeopt.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestUseRTMDeopt.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify that UseRTMDeopt affects uncommon trap installation in
* copmpiled methods with synchronized block.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestUseRTMDeopt
--- a/hotspot/test/compiler/rtm/locking/TestUseRTMForInflatedLocks.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestUseRTMForInflatedLocks.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8031320
* @summary Verify that rtm locking is used for inflated locks.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestUseRTMForInflatedLocks
--- a/hotspot/test/compiler/rtm/locking/TestUseRTMForStackLocks.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestUseRTMForStackLocks.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @test
* @bug 8031320
* @summary Verify that rtm locking is used for stack locks.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestUseRTMForStackLocks
--- a/hotspot/test/compiler/rtm/locking/TestUseRTMXendForLockBusy.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestUseRTMXendForLockBusy.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify that UseRTMXendForLockBusy option affects
* method behaviour if lock is busy.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestUseRTMXendForLockBusy
--- a/hotspot/test/compiler/rtm/method_options/TestNoRTMLockElidingOption.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/method_options/TestNoRTMLockElidingOption.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8031320
* @summary Verify that NoRTMLockEliding option could be applied to
* specified method and that such method will not use rtm.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestNoRTMLockElidingOption
--- a/hotspot/test/compiler/rtm/method_options/TestUseRTMLockElidingOption.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/method_options/TestUseRTMLockElidingOption.java Wed Jul 05 21:02:29 2017 +0200
@@ -28,7 +28,7 @@
* @summary Verify that UseRTMLockEliding option could be applied to
* specified method and that such method will not be deoptimized
* on high abort ratio.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestUseRTMLockElidingOption
--- a/hotspot/test/compiler/rtm/print/TestPrintPreciseRTMLockingStatistics.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/rtm/print/TestPrintPreciseRTMLockingStatistics.java Wed Jul 05 21:02:29 2017 +0200
@@ -29,7 +29,7 @@
* on overall aborts and locks count and count of aborts of
* different types. Test also verify that VM output does not
* contain rtm locking statistics when it should not.
- * @library /testlibrary /../../test/lib /compiler/testlibrary
+ * @library /testlibrary /test/lib /compiler/testlibrary
* @modules java.base/sun.misc
* java.management
* @build TestPrintPreciseRTMLockingStatistics
--- a/hotspot/test/compiler/runtime/8010927/Test8010927.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/runtime/8010927/Test8010927.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8010927
* @summary Kitchensink crashed with SIGSEGV, Problematic frame: v ~StubRoutines::checkcast_arraycopy
- * @library /../../test/lib /testlibrary
+ * @library /test/lib /testlibrary
* @modules java.base/sun.misc
* @build Test8010927
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/stable/TestStableBoolean.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/stable/TestStableBoolean.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
/*
* @test TestStableBoolean
* @summary tests on stable fields and arrays
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build TestStableBoolean StableConfiguration sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main ClassFileInstaller
--- a/hotspot/test/compiler/stable/TestStableByte.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/stable/TestStableByte.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
/*
* @test TestStableByte
* @summary tests on stable fields and arrays
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build TestStableByte StableConfiguration sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main ClassFileInstaller
--- a/hotspot/test/compiler/stable/TestStableChar.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/stable/TestStableChar.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
/*
* @test TestStableChar
* @summary tests on stable fields and arrays
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build TestStableChar StableConfiguration sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main ClassFileInstaller
--- a/hotspot/test/compiler/stable/TestStableDouble.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/stable/TestStableDouble.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
/*
* @test TestStableDouble
* @summary tests on stable fields and arrays
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build TestStableDouble StableConfiguration sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main ClassFileInstaller
--- a/hotspot/test/compiler/stable/TestStableFloat.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/stable/TestStableFloat.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
/*
* @test TestStableFloat
* @summary tests on stable fields and arrays
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build TestStableFloat StableConfiguration sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main ClassFileInstaller
--- a/hotspot/test/compiler/stable/TestStableInt.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/stable/TestStableInt.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
/*
* @test TestStableInt
* @summary tests on stable fields and arrays
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build TestStableInt StableConfiguration sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main ClassFileInstaller
--- a/hotspot/test/compiler/stable/TestStableLong.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/stable/TestStableLong.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
/*
* @test TestStableLong
* @summary tests on stable fields and arrays
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build TestStableLong StableConfiguration sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main ClassFileInstaller
--- a/hotspot/test/compiler/stable/TestStableObject.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/stable/TestStableObject.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
/*
* @test TestStableObject
* @summary tests on stable fields and arrays
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build TestStableObject StableConfiguration sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main ClassFileInstaller
--- a/hotspot/test/compiler/stable/TestStableShort.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/stable/TestStableShort.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
/*
* @test TestStableShort
* @summary tests on stable fields and arrays
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build TestStableShort StableConfiguration sun.hotspot.WhiteBox
* @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main ClassFileInstaller
--- a/hotspot/test/compiler/tiered/ConstantGettersTransitionsTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/tiered/ConstantGettersTransitionsTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
/**
* @test ConstantGettersTransitionsTest
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* @modules java.base/sun.misc
* java.management
* @build TransitionsTestExecutor ConstantGettersTransitionsTest
--- a/hotspot/test/compiler/tiered/LevelTransitionTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/tiered/LevelTransitionTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -28,7 +28,7 @@
/**
* @test LevelTransitionTest
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* @modules java.base/sun.misc
* java.management
* @ignore 8067651
--- a/hotspot/test/compiler/tiered/NonTieredLevelsTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/tiered/NonTieredLevelsTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
/**
* @test NonTieredLevelsTest
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* @modules java.management
* @build NonTieredLevelsTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/tiered/TieredLevelsTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/tiered/TieredLevelsTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -23,7 +23,7 @@
/**
* @test TieredLevelsTest
- * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @library /testlibrary /test/lib /compiler/whitebox
* @modules java.management
* @build TieredLevelsTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/types/correctness/CorrectnessTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/types/correctness/CorrectnessTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test CorrectnessTest
* @bug 8038418
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @ignore 8066173
--- a/hotspot/test/compiler/types/correctness/OffTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/types/correctness/OffTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test CorrectnessTest
* @bug 8038418
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @ignore 8066173
--- a/hotspot/test/compiler/uncommontrap/8009761/Test8009761.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/uncommontrap/8009761/Test8009761.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
/*
* @test
* @bug 8009761
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @summary Deoptimization on sparc doesn't set Llast_SP correctly in the interpreter frames it creates
* @build Test8009761
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/uncommontrap/TestUnstableIfTrap.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/uncommontrap/TestUnstableIfTrap.java Wed Jul 05 21:02:29 2017 +0200
@@ -40,7 +40,7 @@
/*
* @test
* @bug 8030976 8059226
- * @library /testlibrary /compiler/testlibrary /../../test/lib
+ * @library /testlibrary /compiler/testlibrary /test/lib
* @modules java.base/jdk.internal.org.objectweb.asm
* java.base/sun.misc
* java.compiler
--- a/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
/*
* @test
* @summary tests on constant folding of unsafe get operations
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions
* -Xbatch -XX:-TieredCompilation
* -XX:+FoldStableValues
--- a/hotspot/test/compiler/whitebox/AllocationCodeBlobTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/whitebox/AllocationCodeBlobTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -34,7 +34,7 @@
/*
* @test AllocationCodeBlobTest
* @bug 8059624 8064669
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build AllocationCodeBlobTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/whitebox/ClearMethodStateTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/whitebox/ClearMethodStateTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
/*
* @test ClearMethodStateTest
* @bug 8006683 8007288 8022832
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build ClearMethodStateTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test DeoptimizeAllTest
* @bug 8006683 8007288 8022832
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build DeoptimizeAllTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/whitebox/DeoptimizeFramesTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/whitebox/DeoptimizeFramesTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test DeoptimizeFramesTest
* @bug 8028595
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build DeoptimizeFramesTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test DeoptimizeMethodTest
* @bug 8006683 8007288 8022832
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build DeoptimizeMethodTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/whitebox/DeoptimizeMultipleOSRTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/whitebox/DeoptimizeMultipleOSRTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -28,7 +28,7 @@
/*
* @test DeoptimizeMultipleOSRTest
* @bug 8061817
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build DeoptimizeMultipleOSRTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/whitebox/EnqueueMethodForCompilationTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/whitebox/EnqueueMethodForCompilationTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test EnqueueMethodForCompilationTest
* @bug 8006683 8007288 8022832
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build EnqueueMethodForCompilationTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/whitebox/ForceNMethodSweepTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/whitebox/ForceNMethodSweepTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -34,7 +34,7 @@
/*
* @test
* @bug 8059624 8064669
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build ForceNMethodSweepTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/whitebox/GetCodeHeapEntriesTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/whitebox/GetCodeHeapEntriesTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -33,7 +33,7 @@
/*
* @test GetCodeHeapEntriesTest
* @bug 8059624
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build GetCodeHeapEntriesTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/whitebox/GetNMethodTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/whitebox/GetNMethodTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -29,7 +29,7 @@
/*
* @test GetNMethodTest
* @bug 8038240
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build GetNMethodTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test IsMethodCompilableTest
* @bug 8007270 8006683 8007288 8022832
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build jdk.test.lib.* sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/whitebox/LockCompilationTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/whitebox/LockCompilationTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test LockCompilationTest
* @bug 8059624
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build LockCompilationTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test MakeMethodNotCompilableTest
* @bug 8012322 8006683 8007288 8022832
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build MakeMethodNotCompilableTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/whitebox/SetDontInlineMethodTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/whitebox/SetDontInlineMethodTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test SetDontInlineMethodTest
* @bug 8006683 8007288 8022832
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build SetDontInlineMethodTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/compiler/whitebox/SetForceInlineMethodTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/compiler/whitebox/SetForceInlineMethodTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test SetForceInlineMethodTest
* @bug 8006683 8007288 8022832
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build SetForceInlineMethodTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/gc/CondCardMark/Basic.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/CondCardMark/Basic.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @bug 8076987
* @bug 8078438
* @summary Verify UseCondCardMark works
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build Basic
* @run main/othervm -Xint Basic
* @run main/othervm -Xint -XX:+UseCondCardMark Basic
--- a/hotspot/test/gc/TestSmallHeap.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/TestSmallHeap.java Wed Jul 05 21:02:29 2017 +0200
@@ -29,7 +29,7 @@
* @requires vm.compMode != "Xcomp"
* @requires vm.opt.UseCompressedOops != false
* @summary Verify that starting the VM with a small heap works
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management/sun.management
* @build TestSmallHeap
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/gc/arguments/TestCMSHeapSizeFlags.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/arguments/TestCMSHeapSizeFlags.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @key gc
* @bug 8006088
* @summary Tests argument processing for initial and maximum heap size for the CMS collector
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestCMSHeapSizeFlags TestMaxHeapSizeTools
--- a/hotspot/test/gc/arguments/TestG1HeapSizeFlags.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/arguments/TestG1HeapSizeFlags.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @key gc
* @bug 8006088
* @summary Tests argument processing for initial and maximum heap size for the G1 collector
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestG1HeapSizeFlags TestMaxHeapSizeTools
--- a/hotspot/test/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test TestMinAndInitialSurvivorRatioFlags
* @key gc
* @summary Verify that MinSurvivorRatio and InitialSurvivorRatio flags work
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestMinAndInitialSurvivorRatioFlags
--- a/hotspot/test/gc/arguments/TestMinInitialErgonomics.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/arguments/TestMinInitialErgonomics.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @key gc
* @bug 8006088
* @summary Test ergonomics decisions related to minimum and initial heap size.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestMinInitialErgonomics TestMaxHeapSizeTools
--- a/hotspot/test/gc/arguments/TestNewRatioFlag.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/arguments/TestNewRatioFlag.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @key gc
* @bug 8025166
* @summary Verify that heap devided among generations according to NewRatio
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestNewRatioFlag
--- a/hotspot/test/gc/arguments/TestNewSizeFlags.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/arguments/TestNewSizeFlags.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @key gc
* @bug 8025166
* @summary Verify that young gen size conforms values specified by NewSize, MaxNewSize and Xmn options
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestNewSizeFlags
--- a/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @bug 8006088
* @summary Tests argument processing for initial and maximum heap size for the
* parallel collectors.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestParallelHeapSizeFlags TestMaxHeapSizeTools
--- a/hotspot/test/gc/arguments/TestSerialHeapSizeFlags.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/arguments/TestSerialHeapSizeFlags.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @key gc
* @bug 8006088
* @summary Tests argument processing for initial and maximum heap size for the Serial collector
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestSerialHeapSizeFlags TestMaxHeapSizeTools
--- a/hotspot/test/gc/arguments/TestSurvivorRatioFlag.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/arguments/TestSurvivorRatioFlag.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test TestSurvivorRatioFlag
* @key gc
* @summary Verify that actual survivor ratio is equal to specified SurvivorRatio value
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestSurvivorRatioFlag
--- a/hotspot/test/gc/arguments/TestTargetSurvivorRatioFlag.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/arguments/TestTargetSurvivorRatioFlag.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test TestTargetSurvivorRatioFlag
* @key gc
* @summary Verify that option TargetSurvivorRatio affects survivor space occupancy after minor GC.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestTargetSurvivorRatioFlag
--- a/hotspot/test/gc/arguments/TestUseCompressedOopsErgo.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/arguments/TestUseCompressedOopsErgo.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @key gc
* @bug 8010722
* @summary Tests ergonomics for UseCompressedOops.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management/sun.management
* @build TestUseCompressedOopsErgo TestUseCompressedOopsErgoTools
--- a/hotspot/test/gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @key gc
* @bug 8049831
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestCMSClassUnloadingEnabledHWM
--- a/hotspot/test/gc/class_unloading/TestG1ClassUnloadingHWM.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/class_unloading/TestG1ClassUnloadingHWM.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @key gc
* @bug 8049831
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestG1ClassUnloadingHWM
--- a/hotspot/test/gc/g1/TestEagerReclaimHumongousRegionsClearMarkBits.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/g1/TestEagerReclaimHumongousRegionsClearMarkBits.java Wed Jul 05 21:02:29 2017 +0200
@@ -121,6 +121,7 @@
"-XX:G1HeapRegionSize=1M",
"-XX:InitiatingHeapOccupancyPercent=0", // Want to have as much as possible initial marks.
"-XX:+PrintGC",
+ "-XX:+UnlockDiagnosticVMOptions",
"-XX:+VerifyAfterGC",
"-XX:ConcGCThreads=1", // Want to make marking as slow as possible.
"-XX:+IgnoreUnrecognizedVMOptions", // G1VerifyBitmaps is develop only.
--- a/hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @key regression
* @key gc
* @bug 8027756
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestHumongousCodeCacheRoots
--- a/hotspot/test/gc/g1/TestLargePageUseForAuxMemory.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/g1/TestLargePageUseForAuxMemory.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,13 +26,13 @@
* @summary Test that auxiliary data structures are allocated using large pages if available.
* @bug 8058354 8079208
* @key gc
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @requires (vm.gc=="G1" | vm.gc=="null")
* @build jdk.test.lib.* sun.hotspot.WhiteBox
* @build TestLargePageUseForAuxMemory
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main/othervm -Xbootclasspath/a:. -XX:+UseG1GC -XX:+WhiteBoxAPI -XX:+IgnoreUnrecognizedVMOptions -XX:+UseLargePages TestLargePageUseForAuxMemory
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+IgnoreUnrecognizedVMOptions -XX:+UseLargePages TestLargePageUseForAuxMemory
*/
import java.lang.Math;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/TestPLABOutput.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test TestPLABOutput
+ * @bug 8140585
+ * @summary Check that G1 does not report empty PLAB statistics in the first evacuation.
+ * @requires vm.gc=="G1" | vm.gc=="null"
+ * @key gc
+ * @library /testlibrary /../../test/lib
+ * @build sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run driver TestPLABOutput
+ */
+
+import sun.hotspot.WhiteBox;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.Platform;
+import jdk.test.lib.ProcessTools;
+
+import static jdk.test.lib.Asserts.*;
+
+public class TestPLABOutput {
+
+ public static void runTest() throws Exception {
+ final String[] arguments = {
+ "-Xbootclasspath/a:.",
+ "-XX:+UnlockExperimentalVMOptions",
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+WhiteBoxAPI",
+ "-XX:+UseG1GC",
+ "-Xmx10M",
+ "-XX:+PrintGC",
+ "-XX:+PrintPLAB",
+ GCTest.class.getName()
+ };
+
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(arguments);
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+ output.shouldHaveExitValue(0);
+
+ System.out.println(output.getStdout());
+
+ String pattern = "#0:.*allocated = (\\d+).*";
+ Pattern r = Pattern.compile(pattern);
+ Matcher m = r.matcher(output.getStdout());
+
+ if (!m.find()) {
+ throw new RuntimeException("Could not find any PLAB statistics output");
+ }
+ int allocated = Integer.parseInt(m.group(1));
+ assertGT(allocated, 0, "Did not allocate any memory during test");
+ }
+
+ public static void main(String[] args) throws Exception {
+ runTest();
+ }
+
+ static class GCTest {
+ private static final WhiteBox WB = WhiteBox.getWhiteBox();
+
+ public static Object holder;
+
+ public static void main(String [] args) {
+ holder = new byte[100];
+ WB.youngGC();
+ System.out.println(holder);
+ }
+ }
+}
+
--- a/hotspot/test/gc/g1/TestShrinkAuxiliaryData00.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/g1/TestShrinkAuxiliaryData00.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @summary Checks that decommitment occurs for JVM with different
* G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values
* @requires vm.gc=="G1" | vm.gc=="null"
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build jdk.test.lib.* sun.hotspot.WhiteBox
--- a/hotspot/test/gc/g1/TestShrinkAuxiliaryData05.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/g1/TestShrinkAuxiliaryData05.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @summary Checks that decommitment occurs for JVM with different
* G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values
* @requires vm.gc=="G1" | vm.gc=="null"
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build jdk.test.lib.* sun.hotspot.WhiteBox
--- a/hotspot/test/gc/g1/TestShrinkAuxiliaryData10.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/g1/TestShrinkAuxiliaryData10.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @summary Checks that decommitment occurs for JVM with different
* G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values
* @requires vm.gc=="G1" | vm.gc=="null"
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build jdk.test.lib.* sun.hotspot.WhiteBox
--- a/hotspot/test/gc/g1/TestShrinkAuxiliaryData15.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/g1/TestShrinkAuxiliaryData15.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @summary Checks that decommitment occurs for JVM with different
* G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values
* @requires vm.gc=="G1" | vm.gc=="null"
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build jdk.test.lib.* sun.hotspot.WhiteBox
--- a/hotspot/test/gc/g1/TestShrinkAuxiliaryData20.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/g1/TestShrinkAuxiliaryData20.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @summary Checks that decommitment occurs for JVM with different
* G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values
* @requires vm.gc=="G1" | vm.gc=="null"
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build jdk.test.lib.* sun.hotspot.WhiteBox
--- a/hotspot/test/gc/g1/TestShrinkAuxiliaryData25.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/g1/TestShrinkAuxiliaryData25.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @summary Checks that decommitment occurs for JVM with different
* G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values
* @requires vm.gc=="G1" | vm.gc=="null"
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build jdk.test.lib.* sun.hotspot.WhiteBox
--- a/hotspot/test/gc/g1/TestShrinkAuxiliaryData30.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/g1/TestShrinkAuxiliaryData30.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @summary Checks that decommitment occurs for JVM with different
* G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values
* @requires vm.gc=="G1" | vm.gc=="null"
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build jdk.test.lib.* sun.hotspot.WhiteBox
--- a/hotspot/test/gc/g1/humongousObjects/TestHumongousThreshold.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/g1/humongousObjects/TestHumongousThreshold.java Wed Jul 05 21:02:29 2017 +0200
@@ -31,7 +31,7 @@
* @test TestHumongousThreshold
* @summary Checks that objects larger than half a region are allocated as humongous
* @requires vm.gc=="G1" | vm.gc=="null"
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management
* @build sun.hotspot.WhiteBox
* gc.g1.humongousObjects.Helpers
--- a/hotspot/test/gc/g1/mixedgc/TestLogging.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/g1/mixedgc/TestLogging.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test TestLogging
* @summary Check that a mixed GC is reflected in the gc logs
* @requires vm.gc=="G1" | vm.gc=="null"
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @ignore 8138607
* @modules java.management
* @build sun.hotspot.WhiteBox gc.g1.mixedgc.TestLogging
--- a/hotspot/test/gc/metaspace/TestCapacityUntilGCWrapAround.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/metaspace/TestCapacityUntilGCWrapAround.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @key gc
* @bug 8049831
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestCapacityUntilGCWrapAround
--- a/hotspot/test/gc/survivorAlignment/TestAllocationInEden.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/survivorAlignment/TestAllocationInEden.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @bug 8031323
* @summary Verify that object's alignment in eden space is not affected by
* SurvivorAlignmentInBytes option.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestAllocationInEden SurvivorAlignmentTestMain AlignmentHelper
--- a/hotspot/test/gc/survivorAlignment/TestPromotionFromEdenToTenured.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/survivorAlignment/TestPromotionFromEdenToTenured.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @bug 8031323
* @summary Verify that objects promoted from eden space to tenured space during
* full GC are not aligned to SurvivorAlignmentInBytes value.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestPromotionFromEdenToTenured SurvivorAlignmentTestMain
--- a/hotspot/test/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterFullGC.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterFullGC.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @bug 8031323
* @summary Verify that objects promoted from survivor space to tenured space
* during full GC are not aligned to SurvivorAlignmentInBytes value.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestPromotionFromSurvivorToTenuredAfterFullGC
--- a/hotspot/test/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,7 +27,7 @@
* @summary Verify that objects promoted from survivor space to tenured space
* when their age exceeded tenuring threshold are not aligned to
* SurvivorAlignmentInBytes value.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestPromotionFromSurvivorToTenuredAfterMinorGC
--- a/hotspot/test/gc/survivorAlignment/TestPromotionToSurvivor.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/survivorAlignment/TestPromotionToSurvivor.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @bug 8031323
* @summary Verify that objects promoted from eden space to survivor space after
* minor GC are aligned to SurvivorAlignmentInBytes.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestPromotionToSurvivor
--- a/hotspot/test/gc/whitebox/TestConcMarkCycleWB.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/whitebox/TestConcMarkCycleWB.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test TestConMarkCycleWB
* @bug 8065579
* @requires vm.gc=="null" | vm.gc=="G1"
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.compiler
* java.management
--- a/hotspot/test/gc/whitebox/TestWBGC.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/gc/whitebox/TestWBGC.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test TestWBGC
* @bug 8055098
* @summary Test verify that WB methods isObjectInOldGen and youngGC works correctly.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestWBGC
--- a/hotspot/test/runtime/ClassUnload/KeepAliveClass.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/ClassUnload/KeepAliveClass.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test KeepAliveClass
* @summary This test case uses a java.lang.Class instance to keep a class alive.
- * @library /testlibrary /../../test/lib /runtime/testlibrary
+ * @library /testlibrary /test/lib /runtime/testlibrary
* @library classes
* @build KeepAliveClass test.Empty
* @build ClassUnloadCommon
--- a/hotspot/test/runtime/ClassUnload/KeepAliveClassLoader.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/ClassUnload/KeepAliveClassLoader.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test KeepAliveClassLoader
* @summary This test case uses a java.lang.ClassLoader instance to keep a class alive.
- * @library /testlibrary /../../test/lib /runtime/testlibrary
+ * @library /testlibrary /test/lib /runtime/testlibrary
* @library classes
* @build KeepAliveClassLoader test.Empty
* @build ClassUnloadCommon
--- a/hotspot/test/runtime/ClassUnload/KeepAliveObject.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/ClassUnload/KeepAliveObject.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test KeepAliveObject
* @summary This test case uses a class instance to keep the class alive.
- * @library /testlibrary /../../test/lib /runtime/testlibrary
+ * @library /testlibrary /test/lib /runtime/testlibrary
* @library classes
* @build KeepAliveObject test.Empty
* @build ClassUnloadCommon
--- a/hotspot/test/runtime/ClassUnload/KeepAliveSoftReference.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/ClassUnload/KeepAliveSoftReference.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test KeepAliveSoftReference
* @summary This test case uses a java.lang.ref.SoftReference referencing a class instance to keep a class alive.
- * @library /testlibrary /../../test/lib /runtime/testlibrary
+ * @library /testlibrary /test/lib /runtime/testlibrary
* @library classes
* @build KeepAliveSoftReference test.Empty
* @build ClassUnloadCommon
--- a/hotspot/test/runtime/ClassUnload/UnloadTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/ClassUnload/UnloadTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test UnloadTest
- * @library /runtime/testlibrary /testlibrary /../../test/lib
+ * @library /runtime/testlibrary /testlibrary /test/lib
* @library classes
* @build ClassUnloadCommon test.Empty
* @build UnloadTest
--- a/hotspot/test/runtime/CompressedOops/UseCompressedOops.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/CompressedOops/UseCompressedOops.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,6 +26,7 @@
* @bug 8022865
* @summary Tests for different combination of UseCompressedOops options
* @library /testlibrary
+ * @ignore 8079353
* @modules java.base/sun.misc
* java.management
* @run main UseCompressedOops
--- a/hotspot/test/runtime/ErrorHandling/SecondaryErrorTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/ErrorHandling/SecondaryErrorTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -28,6 +28,7 @@
* @summary Synchronous signals during error reporting may terminate or hang VM process
* @library /testlibrary
* @author Thomas Stuefe (SAP)
+ * @requires os.family != "mac"
* @modules java.base/sun.misc
* java.management
*/
--- a/hotspot/test/runtime/NMT/ChangeTrackingLevel.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/NMT/ChangeTrackingLevel.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @bug 8059100
* @summary Test that you can decrease NMT tracking level but not increase it.
* @key nmt
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build ChangeTrackingLevel
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
--- a/hotspot/test/runtime/NMT/JcmdDetailDiff.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/NMT/JcmdDetailDiff.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @summary run NMT baseline, allocate memory and verify output from detail.diff
* @key nmt jcmd
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build JcmdDetailDiff
--- a/hotspot/test/runtime/NMT/JcmdSummaryDiff.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/NMT/JcmdSummaryDiff.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @summary run NMT baseline, allocate memory and verify output from summary.diff
* @key nmt jcmd
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build JcmdSummaryDiff
--- a/hotspot/test/runtime/NMT/MallocRoundingReportTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/NMT/MallocRoundingReportTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @summary Test consistency of NMT by creating allocations of the Test type with various sizes and verifying visibility with jcmd
* @key nmt jcmd
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build MallocRoundingReportTest
--- a/hotspot/test/runtime/NMT/MallocSiteHashOverflow.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/NMT/MallocSiteHashOverflow.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @summary Test corner case that overflows malloc site hashtable bucket
* @requires sun.arch.data.model == "32"
* @key nmt jcmd stress
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build MallocSiteHashOverflow
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail MallocSiteHashOverflow
--- a/hotspot/test/runtime/NMT/MallocStressTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/NMT/MallocStressTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @summary Stress test for malloc tracking
* @key nmt jcmd stress
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build MallocStressTest
--- a/hotspot/test/runtime/NMT/MallocTestType.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/NMT/MallocTestType.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @summary Test consistency of NMT by leaking a few select allocations of the Test type and then verify visibility with jcmd
* @key nmt jcmd
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build MallocTestType
--- a/hotspot/test/runtime/NMT/MallocTrackingVerify.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/NMT/MallocTrackingVerify.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @bug 8054836
* @summary Test to verify correctness of malloc tracking
* @key nmt jcmd
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build MallocTrackingVerify
--- a/hotspot/test/runtime/NMT/ReleaseCommittedMemory.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/NMT/ReleaseCommittedMemory.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @bug 8013120
* @summary Release committed memory and make sure NMT handles it correctly
* @key nmt regression
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build ReleaseCommittedMemory
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
--- a/hotspot/test/runtime/NMT/ReleaseNoCommit.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/NMT/ReleaseNoCommit.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @summary Release uncommitted memory and make sure NMT handles it correctly
* @key nmt regression
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build ReleaseNoCommit
--- a/hotspot/test/runtime/NMT/SummarySanityCheck.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/NMT/SummarySanityCheck.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @key nmt jcmd
* @summary Sanity check the output of NMT
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build SummarySanityCheck
--- a/hotspot/test/runtime/NMT/ThreadedMallocTestType.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/NMT/ThreadedMallocTestType.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @key nmt jcmd
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build ThreadedMallocTestType
--- a/hotspot/test/runtime/NMT/ThreadedVirtualAllocTestType.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/NMT/ThreadedVirtualAllocTestType.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @key nmt jcmd
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build ThreadedVirtualAllocTestType
--- a/hotspot/test/runtime/NMT/VirtualAllocCommitUncommitRecommit.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/NMT/VirtualAllocCommitUncommitRecommit.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @summary Test reserve/commit/uncommit/release of virtual memory and that we track it correctly
* @key nmt jcmd
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build VirtualAllocCommitUncommitRecommit
--- a/hotspot/test/runtime/NMT/VirtualAllocTestType.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/NMT/VirtualAllocTestType.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @summary Test Reserve/Commit/Uncommit/Release of virtual memory and that we track it correctly
* @key nmt jcmd
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build VirtualAllocTestType
--- a/hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency1.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency1.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8047290
* @summary Ensure that a Monitor::lock_without_safepoint_check fires an assert when it incorrectly acquires a lock which must always have safepoint checks.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build AssertSafepointCheckConsistency1
--- a/hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency2.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency2.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8047290
* @summary Ensure that a Monitor::lock fires an assert when it incorrectly acquires a lock which must never have safepoint checks.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build AssertSafepointCheckConsistency2
--- a/hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency3.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency3.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8047290
* @summary Ensure that Monitor::lock_without_safepoint_check does not assert when it correctly acquires a lock which must never have safepoint checks.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build AssertSafepointCheckConsistency3
--- a/hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency4.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/Safepoint/AssertSafepointCheckConsistency4.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8047290
* @summary Ensure that Monitor::lock does not assert when it correctly acquires a lock which must always have safepoint checks.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build AssertSafepointCheckConsistency4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SameObject/SameObject.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @key cte_test
+ * @bug 4784641
+ * @summary -Xcheck:jni overly strict in JNI method IsSameObject
+ * Fixed in JDK1.3.1_10
+ * Fixed in JDK1.4.1_07
+ * @library /testlibrary
+ * @run main/othervm/native -Xcheck:jni SameObject
+ */
+public class SameObject {
+
+ public Object obj = new Object();
+
+ static {
+ System.loadLibrary("SameObject");
+ }
+
+ public native void createWeakRef(Object obj);
+
+ public native int checkWeakRef();
+
+ public static void main(String[] args) throws Exception {
+ SameObject sameObject = new SameObject();
+
+ int result = sameObject.test();
+ Asserts.assertEquals(result, 0, "WeakRef still alive");
+ }
+
+ public int test() {
+ createWeakRef(obj);
+ obj = null;
+ System.gc();
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ex) {
+ System.out.println("Interrupted");
+ }
+
+ return checkWeakRef();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SameObject/libSameObject.c Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <jni.h>
+
+static jobject weakRef;
+
+/*
+ * Class: SameObject
+ * Method: createWeakRef
+ * Signature: (Ljava/lang/Object;)V
+ */
+JNIEXPORT void JNICALL Java_SameObject_createWeakRef
+(JNIEnv *env, jobject obj1, jobject obj2) {
+ weakRef = (*env)->NewWeakGlobalRef(env, obj2);
+}
+
+/*
+ * Class: SameObject
+ * Method: checkWeakRef
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_SameObject_checkWeakRef
+(JNIEnv *env, jobject obj) {
+ return (*env)->IsSameObject(env, weakRef, NULL) ? 0 : 1;
+}
--- a/hotspot/test/runtime/SharedArchiveFile/SharedStrings.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/SharedArchiveFile/SharedStrings.java Wed Jul 05 21:02:29 2017 +0200
@@ -29,7 +29,7 @@
* @requires (sun.arch.data.model != "32") & (os.family != "windows")
* @requires (vm.opt.UseCompressedOops == null) | (vm.opt.UseCompressedOops == true)
* @requires (vm.gc=="G1" | vm.gc=="null")
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build SharedStringsWb SharedStrings BasicJarBuilder sun.hotspot.WhiteBox
--- a/hotspot/test/runtime/classFileParserBug/BadInitMethod.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/classFileParserBug/BadInitMethod.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,29 +26,59 @@
* @test
* @bug 8130669
* @summary VM prohibits <clinit> methods with return values
- * @compile ignoredClinit.jasm
+ * @compile nonvoidClinit.jasm
+ * @compile clinitNonStatic.jasm
+ * @compile clinitArg.jasm
+ * @compile clinitArg51.jasm
* @compile badInit.jasm
* @run main/othervm -Xverify:all BadInitMethod
*/
-// Test that a non-void <clinit> method does not cause an exception to be
-// thrown. But that a non-void <init> method causes a ClassFormatError
-// exception.
+// Test that non-void <clinit>, non-static <clinit>, and non-void
+// <init> methods cause ClassFormatException's to be thrown.
public class BadInitMethod {
public static void main(String args[]) throws Throwable {
System.out.println("Regression test for bug 8130669");
try {
- Class newClass = Class.forName("ignoredClinit");
- } catch (java.lang.Throwable e) {
- throw new RuntimeException("Unexpected exception: " + e.getMessage());
+ Class newClass = Class.forName("nonvoidClinit");
+ throw new RuntimeException(
+ "Expected ClassFormatError exception for non-void <clinit> not thrown");
+ } catch (java.lang.ClassFormatError e) {
+ System.out.println("Test BadInitMethod passed for non-void <clinit>");
+ }
+
+ try {
+ Class newClass = Class.forName("clinitNonStatic");
+ throw new RuntimeException(
+ "Expected ClassFormatError exception for non-static <clinit> not thrown");
+ } catch (java.lang.ClassFormatError e) {
+ System.out.println("Test BadInitMethod passed for non-static <clinit>");
+ }
+
+ // <clinit> with args is allowed in class file version < 51.
+ try {
+ Class newClass = Class.forName("clinitArg");
+ } catch (java.lang.ClassFormatError e) {
+ throw new RuntimeException(
+ "Unexpected ClassFormatError exception for <clinit> with argument in class file < 51");
+ }
+
+ // <clinit> with args is not allowed in class file version >= 51.
+ try {
+ Class newClass = Class.forName("clinitArg51");
+ throw new RuntimeException(
+ "Expected ClassFormatError exception for <clinit> with argument not thrown");
+ } catch (java.lang.ClassFormatError e) {
+ System.out.println("Test BadInitMethod passed for <clinit> with argument");
}
try {
Class newClass = Class.forName("badInit");
- throw new RuntimeException("Expected ClassFormatError exception not thrown");
+ throw new RuntimeException(
+ "Expected ClassFormatError exception for non-void <init> not thrown");
} catch (java.lang.ClassFormatError e) {
- System.out.println("Test BadInitMethod passed");
+ System.out.println("Test BadInitMethod passed for non-void <init>");
}
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/clinitArg.jasm Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// This class contains a <clinit> method with signature: (I)V. The JVM should
+// not throw ClassFormatError because methods named <clinit> that have arguments
+// are not illegal in class file versions < 51.
+
+public class clinitArg version 50:0
+{
+
+ public static Method "<clinit>":"(I)V"
+ stack 1 locals 1
+ {
+ iconst_0;
+ return;
+ }
+
+} // end Class clinitArg
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/clinitArg51.jasm Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// This class contains a <clinit> method with signature: (I)V. The JVM should
+// throw ClassFormatError because methods named <clinit> that have arguments
+// are illegal in class file version >= 51.
+
+public class clinitArg51 version 51:0
+{
+
+ public static Method "<clinit>":"(I)V"
+ stack 1 locals 1
+ {
+ iconst_0;
+ return;
+ }
+
+} // end Class clinitArg51
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/clinitNonStatic.jasm Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// This class contains a non-static <clinit> method. The JVM should
+// throw ClassFormatError because methods named <clinit> must be static
+// in class file versions >= 51.
+
+public class clinitNonStatic version 51:0
+{
+
+ public Method "<clinit>":"()V"
+ stack 1 locals 1
+ {
+ iconst_0;
+ return;
+ }
+
+} // end Class clinitNonStatic
--- a/hotspot/test/runtime/classFileParserBug/ignoredClinit.jasm Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-// This class contains a <clinit> method with signature: ()I. The JVM should
-// not complain about this because methods named <clinit> that have arguments
-// and/or are not void should be ignored by the JVM.
-
-public class ignoredClinit version 51:0
-{
-
- public static Method "<clinit>":"()I"
- stack 1 locals 1
- {
- iconst_0;
- ireturn;
- }
-
-} // end Class ignoredClinit
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/nonvoidClinit.jasm Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// This class contains a <clinit> method with signature: ()I. The JVM should
+// throw ClassFormatError because methods named <clinit> that are not void
+// are illegal.
+
+public class nonvoidClinit version 51:0
+{
+
+ public static Method "<clinit>":"()I"
+ stack 1 locals 1
+ {
+ iconst_0;
+ ireturn;
+ }
+
+} // end Class nonvoidClinit
--- a/hotspot/test/runtime/interned/SanityTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/interned/SanityTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test SanityTest
* @summary Sanity check of String.intern() & GC
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build SanityTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/logging/DefaultMethodsTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8139564
+ * @summary defaultmethods=debug should have logging from each of the statements in the code
+ * @library /testlibrary
+ * @modules java.base/sun.misc
+ * java.management
+ * @run main DefaultMethodsTest
+ */
+
+import jdk.test.lib.*;
+
+public class DefaultMethodsTest {
+ public static void main(String[] args) throws Exception {
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+ "-Xlog:defaultmethods=debug", "-version");
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldContain("Slots that need filling:");
+ output.shouldContain("requires default method processing");
+ output.shouldContain("Looking for default methods for slot ");
+ output.shouldContain("Creating defaults and overpasses...");
+ output.shouldContain("for slot: ");
+ output.shouldContain("Default method processing complete");
+ output.shouldContain("overpass methods");
+ output.shouldContain("default methods");
+ output.shouldHaveExitValue(0);
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/logging/SafepointTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8140348
+ * @summary safepoint=trace should have output from each log statement in the code
+ * @library /testlibrary
+ * @compile SafepointTestMain.java
+ * @modules java.base/sun.misc
+ * java.management
+ * @build SafepointTest
+ * @run main SafepointTest
+ */
+
+import jdk.test.lib.*;
+
+public class SafepointTest {
+ public static void main(String[] args) throws Exception {
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+ "-Xlog:safepoint=trace", "SafepointTestMain");
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldContain("Safepoint synchronization initiated. (");
+ output.shouldContain(" thread(s) to block");
+ output.shouldContain("Entering safepoint region: ");
+ output.shouldContain("Leaving safepoint region");
+ output.shouldContain("_at_poll_safepoint");
+ output.shouldContain("... found polling page ");
+ output.shouldHaveExitValue(0);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/logging/SafepointTestMain.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.ref.WeakReference;
+
+public class SafepointTestMain {
+ public static class B {
+ static int count = 0;
+ public static volatile boolean stop = false;
+ static void localSleep(int time) {
+ try{
+ Thread.currentThread().sleep(time);
+ } catch(InterruptedException ie) {
+ }
+ }
+
+ public static void infinite() {
+ while (!stop) { count++; }
+ }
+ }
+
+ public static byte[] garbage;
+ public static volatile WeakReference<Object> weakref;
+
+ public static void createweakref() {
+ Object o = new Object();
+ weakref = new WeakReference<>(o);
+ }
+
+ public static void main(String[] args) throws Exception {
+ // Run function in separate thread to force compilation and pint safepoint
+ // message for compiled method
+ new Thread() {
+ public void run() {
+ B.infinite();
+ }
+ }.start();
+ B.localSleep(1000);
+ // Cause several safepoints to run GC while the compiled method is running,
+ // to see safepoint messages
+ for (int i = 0; i < 2; i++) {
+ createweakref();
+ while(weakref.get() != null) {
+ garbage = new byte[8192];
+ System.gc();
+ }
+ }
+ B.stop = true;
+ }
+}
--- a/hotspot/test/runtime/memory/ReadFromNoaccessArea.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/memory/ReadFromNoaccessArea.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @summary Test that touching noaccess area in class ReservedHeapSpace results in SIGSEGV/ACCESS_VIOLATION
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build ReadFromNoaccessArea
--- a/hotspot/test/runtime/memory/ReadVMPageSize.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/memory/ReadVMPageSize.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @summary Using WhiteBox to get VM page size
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build ReadVMPageSize
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ReadVMPageSize
--- a/hotspot/test/runtime/memory/ReserveMemory.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/memory/ReserveMemory.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,7 +26,7 @@
* @key regression
* @bug 8012015
* @summary Make sure reserved (but uncommitted) memory is not accessible
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build ReserveMemory
--- a/hotspot/test/runtime/memory/RunUnitTestsConcurrently.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/memory/RunUnitTestsConcurrently.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @summary Test launches unit tests inside vm concurrently
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build RunUnitTestsConcurrently
--- a/hotspot/test/runtime/memory/StressVirtualSpaceResize.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/memory/StressVirtualSpaceResize.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @summary Stress test that expands/shrinks VirtualSpace
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build StressVirtualSpaceResize
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
--- a/hotspot/test/runtime/whitebox/WBStackSize.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/runtime/whitebox/WBStackSize.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test WBStackSize
* @summary verify that whitebox functions getThreadFullStackSize() and getThreadRemainingStackSize are working
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build WBStackSize
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
--- a/hotspot/test/sanity/WBApi.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/sanity/WBApi.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test WBApi
* @summary verify that whitebox functions can be linked and executed
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build WBApi
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
--- a/hotspot/test/serviceability/ParserTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/serviceability/ParserTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @summary Test that the diagnostic command arguemnt parser works
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @build ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.parser.*
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
--- a/hotspot/test/serviceability/dcmd/gc/HeapDumpAllTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/serviceability/dcmd/gc/HeapDumpAllTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @summary Test of diagnostic command GC.heap_dump -all=true
* @library /testlibrary
- * @library /../../test/lib/share/classes
+ * @library /test/lib/share/classes
* @modules java.base/sun.misc
* java.compiler
* java.management
--- a/hotspot/test/serviceability/dcmd/gc/HeapDumpTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/serviceability/dcmd/gc/HeapDumpTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -41,7 +41,7 @@
* @test
* @summary Test of diagnostic command GC.heap_dump
* @library /testlibrary
- * @library /../../test/lib/share/classes
+ * @library /test/lib/share/classes
* @modules java.base/sun.misc
* java.compiler
* java.management
@@ -66,6 +66,7 @@
String cmd = "GC.heap_dump " + heapDumpArgs + " " + dump.getAbsolutePath();
executor.execute(cmd);
+ verifyHeapDump(dump);
dump.delete();
}
--- a/hotspot/test/serviceability/sa/DeadlockDetectionTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/serviceability/sa/DeadlockDetectionTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -38,7 +38,7 @@
/*
* @test
* @summary Test deadlock detection
- * @library /../../test/lib/share/classes
+ * @library /test/lib/share/classes
* @library /testlibrary
* @modules java.management
* @build jdk.test.lib.*
--- a/hotspot/test/serviceability/sa/TestClassLoaderStats.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/serviceability/sa/TestClassLoaderStats.java Wed Jul 05 21:02:29 2017 +0200
@@ -32,7 +32,7 @@
/*
* @test
- * @library /../../test/lib/share/classes
+ * @library /test/lib/share/classes
* @library /testlibrary
* @build jdk.test.lib.*
* @build jdk.test.lib.apps.*
--- a/hotspot/test/serviceability/sa/TestStackTrace.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/serviceability/sa/TestStackTrace.java Wed Jul 05 21:02:29 2017 +0200
@@ -32,7 +32,7 @@
/*
* @test
- * @library /../../test/lib/share/classes
+ * @library /test/lib/share/classes
* @library /testlibrary
* @build jdk.test.lib.*
* @build jdk.test.lib.apps.*
--- a/hotspot/test/testlibrary_tests/TestPlatformIsTieredSupported.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/testlibrary_tests/TestPlatformIsTieredSupported.java Wed Jul 05 21:02:29 2017 +0200
@@ -28,7 +28,7 @@
/**
* @test
* @summary Verifies that Platform::isTieredSupported returns correct value.
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management
* @build TestPlatformIsTieredSupported
--- a/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8012447
- * @library /testlibrary /../../test/lib /testlibrary/ctw/src
+ * @library /testlibrary /test/lib /testlibrary/ctw/src
* @modules java.base/sun.misc
* java.base/sun.reflect
* java.management
--- a/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8012447
- * @library /testlibrary /../../test/lib /testlibrary/ctw/src
+ * @library /testlibrary /test/lib /testlibrary/ctw/src
* @modules java.base/sun.misc
* java.base/sun.reflect
* java.management
--- a/hotspot/test/testlibrary_tests/ctw/JarDirTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/testlibrary_tests/ctw/JarDirTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8012447
- * @library /testlibrary /../../test/lib /testlibrary/ctw/src
+ * @library /testlibrary /test/lib /testlibrary/ctw/src
* @modules java.base/sun.misc
* java.base/sun.reflect
* java.compiler
--- a/hotspot/test/testlibrary_tests/ctw/JarsTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/testlibrary_tests/ctw/JarsTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8012447
- * @library /testlibrary /../../test/lib /testlibrary/ctw/src
+ * @library /testlibrary /test/lib /testlibrary/ctw/src
* @modules java.base/sun.misc
* java.base/sun.reflect
* java.compiler
--- a/hotspot/test/testlibrary_tests/whitebox/BlobSanityTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/testlibrary_tests/whitebox/BlobSanityTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test BlobSanityTest
* @bug 8132980
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management/sun.management
* @build BlobSanityTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/BooleanTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/BooleanTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test BooleanTest
* @bug 8028756
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.compiler
* java.management/sun.management
--- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/DoubleTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/DoubleTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test DoubleTest
* @bug 8028756
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management/sun.management
* @build DoubleTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/IntxTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/IntxTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test IntxTest
* @bug 8028756
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management/sun.management
* @build IntxTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/SizeTTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/SizeTTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test SizeTTest
* @bug 8054823
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management/sun.management
* @build SizeTTest
--- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/StringTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/StringTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test StringTest
* @bug 8028756
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management/sun.management
* @build StringTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/Uint64Test.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/Uint64Test.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test Uint64Test
* @bug 8028756
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.management/sun.management
* @build Uint64Test
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/UintxTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/UintxTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test UintxTest
* @bug 8028756
- * @library /testlibrary /../../test/lib
+ * @library /testlibrary /test/lib
* @modules java.base/sun.misc
* java.management/sun.management
* @build UintxTest
--- a/jaxp/.hgtags Fri Nov 20 15:40:23 2015 -0800
+++ b/jaxp/.hgtags Wed Jul 05 21:02:29 2017 +0200
@@ -335,3 +335,4 @@
35f68242b624112cb6ef7e6226059674d6b499f4 jdk9-b90
ffaff3d0ad0e0ca1e632b80826afa8729ee72a48 jdk9-b91
fcabfb3c38ac1da99394e821902537d92e45222d jdk9-b92
+b9c50c63305cf1120263f6b7c6993021b53c2c40 jdk9-b93
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/XPath.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/XPath.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,9 +25,12 @@
import com.sun.org.apache.xerces.internal.util.XMLSymbols;
import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
import com.sun.org.apache.xerces.internal.xni.QName;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
-import java.util.Vector;
+import java.util.stream.Collectors;
/**
* Bare minimum XPath parser.
@@ -47,20 +50,18 @@
private static final boolean DEBUG_XPATH_PARSE = DEBUG_ALL || false;
- private static final boolean DEBUG_ANY = DEBUG_XPATH_PARSE;
-
//
// Data
//
/** Expression. */
- protected String fExpression;
+ protected final String fExpression;
/** Symbol table. */
- protected SymbolTable fSymbolTable;
+ protected final SymbolTable fSymbolTable;
/** Location paths. */
- protected LocationPath[] fLocationPaths;
+ protected final LocationPath[] fLocationPaths;
//
// Constructors
@@ -72,7 +73,7 @@
throws XPathException {
fExpression = xpath;
fSymbolTable = symbolTable;
- parseExpression(context);
+ fLocationPaths = parseExpression(context);
} // <init>(String,SymbolTable,NamespaceContext)
//
@@ -101,15 +102,14 @@
//
/** Returns a string representation of this object. */
+ @Override
public String toString() {
- StringBuffer buf=new StringBuffer();
- for (int i=0;i<fLocationPaths.length;i++){
- if (i>0){
- buf.append("|");
- }
- buf.append(fLocationPaths[i].toString());
- }
- return buf.toString();
+ final List<LocationPath> l = Arrays.asList(fLocationPaths);
+ final String s = l.stream()
+ .map(aPath -> aPath.toString())
+ .collect(Collectors.joining("|"));
+
+ return s;
} // toString():String
//
@@ -132,12 +132,12 @@
* to build a {@link LocationPath} object from the accumulated
* {@link Step}s.
*/
- private LocationPath buildLocationPath( Vector stepsVector ) throws XPathException {
+ private LocationPath buildLocationPath( ArrayList<Step> stepsVector ) throws XPathException {
int size = stepsVector.size();
check(size!=0);
Step[] steps = new Step[size];
- stepsVector.copyInto(steps);
- stepsVector.removeAllElements();
+ steps = stepsVector.toArray(steps);
+ stepsVector.clear();
return new LocationPath(steps);
}
@@ -146,7 +146,7 @@
* This method is implemented by using the XPathExprScanner and
* examining the list of tokens that it returns.
*/
- private void parseExpression(final NamespaceContext context)
+ private LocationPath[] parseExpression(final NamespaceContext context)
throws XPathException {
// tokens
@@ -184,8 +184,8 @@
throw new XPathException("c-general-xpath");
//fTokens.dumpTokens();
- Vector stepsVector = new Vector();
- Vector locationPathsVector= new Vector();
+ ArrayList<Step> stepsVector = new ArrayList<>();
+ ArrayList<LocationPath> locationPathsVector= new ArrayList<>();
// true when the next token should be 'Step' (as defined in
// the production rule [3] of XML Schema P1 section 3.11.6
@@ -194,28 +194,39 @@
// this is to make sure we can detect a token list like
// 'abc' '/' '/' 'def' 'ghi'
boolean expectingStep = true;
- boolean expectingDoubleColon = false;
- while(xtokens.hasMore()) {
+ while (xtokens.hasMore()) {
final int token = xtokens.nextToken();
switch (token) {
case XPath.Tokens.EXPRTOKEN_OPERATOR_UNION :{
check(!expectingStep);
- locationPathsVector.addElement(buildLocationPath(stepsVector));
+ locationPathsVector.add(buildLocationPath(stepsVector));
expectingStep=true;
break;
}
-
case XPath.Tokens.EXPRTOKEN_ATSIGN: {
check(expectingStep);
Step step = new Step(
new Axis(Axis.ATTRIBUTE),
parseNodeTest(xtokens.nextToken(),xtokens,context));
- stepsVector.addElement(step);
+ stepsVector.add(step);
expectingStep=false;
break;
}
+ case XPath.Tokens.EXPRTOKEN_AXISNAME_ATTRIBUTE: {
+ check(expectingStep);
+ // If we got here we're expecting attribute::
+ if (xtokens.nextToken() != XPath.Tokens.EXPRTOKEN_DOUBLE_COLON) {
+ throw new XPathException("c-general-xpath");
+ }
+ Step step = new Step(
+ new Axis(Axis.ATTRIBUTE),
+ parseNodeTest(xtokens.nextToken(),xtokens,context));
+ stepsVector.add(step);
+ expectingStep = false;
+ break;
+ }
case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY:
case XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE:
case XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME: {
@@ -223,11 +234,23 @@
Step step = new Step(
new Axis(Axis.CHILD),
parseNodeTest(token,xtokens,context));
- stepsVector.addElement(step);
+ stepsVector.add(step);
expectingStep=false;
break;
}
-
+ case XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD: {
+ check(expectingStep);
+ // If we got here we're expecting child::
+ if (xtokens.nextToken() != XPath.Tokens.EXPRTOKEN_DOUBLE_COLON) {
+ throw new XPathException("c-general-xpath");
+ }
+ Step step = new Step(
+ new Axis(Axis.CHILD),
+ parseNodeTest(xtokens.nextToken(),xtokens,context));
+ stepsVector.add(step);
+ expectingStep = false;
+ break;
+ }
case XPath.Tokens.EXPRTOKEN_PERIOD: {
check(expectingStep);
expectingStep=false;
@@ -237,12 +260,12 @@
// This amounts to shorten "a/././b/./c" to "a/b/c".
// Also, the matcher fails to work correctly if XPath
// has those redundant dots.
- if (stepsVector.size()==0) {
+ if (stepsVector.isEmpty()) {
// build step
Axis axis = new Axis(Axis.SELF);
NodeTest nodeTest = new NodeTest(NodeTest.NODE);
Step step = new Step(axis, nodeTest);
- stepsVector.addElement(step);
+ stepsVector.add(step);
if( xtokens.hasMore()
&& xtokens.peekToken() == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH){
@@ -253,67 +276,41 @@
axis = new Axis(Axis.DESCENDANT);
nodeTest = new NodeTest(NodeTest.NODE);
step = new Step(axis, nodeTest);
- stepsVector.addElement(step);
+ stepsVector.add(step);
expectingStep=true;
}
}
break;
}
-
case XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH:{
- // this cannot appear in arbitrary position.
+ // this cannot appear in an arbitrary position.
// it is only allowed right after '.' when
// '.' is the first token of a location path.
throw new XPathException("c-general-xpath");
}
+ case XPath.Tokens.EXPRTOKEN_DOUBLE_COLON: {
+ // :: cannot appear in an arbitrary position.
+ // We only expect this token if the xpath
+ // contains child:: or attribute::
+ throw new XPathException("c-general-xpath");
+ }
case XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH: {
check(!expectingStep);
expectingStep=true;
break;
}
- case XPath.Tokens.EXPRTOKEN_AXISNAME_ATTRIBUTE: {
- check(expectingStep);
- expectingDoubleColon = true;
-
- if (xtokens.nextToken() == XPath.Tokens.EXPRTOKEN_DOUBLE_COLON){
- Step step = new Step(
- new Axis(Axis.ATTRIBUTE),
- parseNodeTest(xtokens.nextToken(),xtokens,context));
- stepsVector.addElement(step);
- expectingStep=false;
- expectingDoubleColon = false;
- }
- break;
- }
- case XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD:{
- check(expectingStep);
- expectingDoubleColon = true;
- break;
- }
- case XPath.Tokens.EXPRTOKEN_DOUBLE_COLON :{
- check(expectingStep);
- check(expectingDoubleColon);
- expectingDoubleColon = false;
- break;
- }
default:
// we should have covered all the tokens that we can possibly see.
- throw new XPathException("c-general-xpath");
- }
+ throw new InternalError();
+ }
}
check(!expectingStep);
- locationPathsVector.addElement(buildLocationPath(stepsVector));
+ locationPathsVector.add(buildLocationPath(stepsVector));
- // save location path
- fLocationPaths=new LocationPath[locationPathsVector.size()];
- locationPathsVector.copyInto(fLocationPaths);
-
-
- if (DEBUG_XPATH_PARSE) {
- System.out.println(">>> "+fLocationPaths);
- }
+ // return location path
+ return locationPathsVector.toArray(new LocationPath[locationPathsVector.size()]);
} // parseExpression(SymbolTable,NamespaceContext)
@@ -378,7 +375,7 @@
//
/** List of steps. */
- public Step[] steps;
+ public final Step[] steps;
//
// Constructors
@@ -445,10 +442,10 @@
//
/** Axis. */
- public Axis axis;
+ public final Axis axis;
/** Node test. */
- public NodeTest nodeTest;
+ public final NodeTest nodeTest;
//
// Constructors
@@ -525,7 +522,7 @@
//
/** Axis type. */
- public short type;
+ public final short type;
//
// Constructors
@@ -594,7 +591,7 @@
//
/** Node test type. */
- public short type;
+ public final short type;
/** Node qualified name. */
public final QName name = new QName();
@@ -856,13 +853,13 @@
private int[] fTokens = new int[INITIAL_TOKEN_COUNT];
private int fTokenCount = 0; // for writing
- private SymbolTable fSymbolTable;
+ private final SymbolTable fSymbolTable;
// REVISIT: Code something better here. -Ac
- private Map<String, Integer> fSymbolMapping = new HashMap<>();
+ private final Map<String, Integer> fSymbolMapping = new HashMap<>();
// REVISIT: Code something better here. -Ac
- private Map<Integer, String> fTokenNames = new HashMap<>();
+ private final Map<Integer, String> fTokenNames = new HashMap<>();
/**
* Current position in the token list.
@@ -1888,6 +1885,10 @@
tokens.addToken(nameHandle);
}
break;
+ default:
+ // CHARTYPE_INVALID or CHARTYPE_OTHER
+ // We're not expecting to find either of these in a valid expression.
+ return false;
}
}
if (XPath.Tokens.DUMP_TOKENS) {
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/XPathException.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/XPathException.java Wed Jul 05 21:02:29 2017 +0200
@@ -3,11 +3,12 @@
* DO NOT REMOVE OR ALTER!
*/
/*
- * Copyright 2001, 2002,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
@@ -37,7 +38,7 @@
// Data
// hold the value of the key this Exception refers to.
- private String fKey;
+ private final String fKey;
//
// Constructors
//
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/BMPattern.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/BMPattern.java Wed Jul 05 21:02:29 2017 +0200
@@ -3,11 +3,12 @@
* DO NOT REMOVE OR ALTER!
*/
/*
- * Copyright 1999-2002,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
@@ -29,9 +30,9 @@
*
*/
public class BMPattern {
- char[] pattern;
- int[] shiftTable;
- boolean ignoreCase;
+ final char[] pattern;
+ final int[] shiftTable;
+ final boolean ignoreCase;
public BMPattern(String pat, boolean ignoreCase) {
this(pat, 256, ignoreCase);
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/CaseInsensitiveMap.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/CaseInsensitiveMap.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,32 +24,27 @@
/**
*/
-public class CaseInsensitiveMap {
+final class CaseInsensitiveMap {
- private static int CHUNK_SHIFT = 10; /* 2^10 = 1k */
- private static int CHUNK_SIZE = (1<<CHUNK_SHIFT);
- private static int CHUNK_MASK = (CHUNK_SIZE-1);
- private static int INITIAL_CHUNK_COUNT = 64; /* up to 0xFFFF */
+ private static final int CHUNK_SHIFT = 10; /* 2^10 = 1k */
+ private static final int CHUNK_SIZE = (1<<CHUNK_SHIFT);
+ private static final int CHUNK_MASK = (CHUNK_SIZE-1);
+ private static final int INITIAL_CHUNK_COUNT = 64; /* up to 0xFFFF */
private static int[][][] caseInsensitiveMap;
- private static Boolean mapBuilt = Boolean.FALSE;
+
+ private static final int LOWER_CASE_MATCH = 1;
+ private static final int UPPER_CASE_MATCH = 2;
- private static int LOWER_CASE_MATCH = 1;
- private static int UPPER_CASE_MATCH = 2;
+ static {
+ buildCaseInsensitiveMap();
+ }
/**
* Return a list of code point characters (not including the input value)
* that can be substituted in a case insensitive match
*/
static public int[] get(int codePoint) {
- if (mapBuilt == Boolean.FALSE) {
- synchronized (mapBuilt) {
- if (mapBuilt == Boolean.FALSE) {
- buildCaseInsensitiveMap();
- }
- } // synchronized
- } // if mapBuilt
-
return (codePoint < 0x10000) ? getMapping(codePoint) : null;
}
@@ -61,11 +56,7 @@
}
private static void buildCaseInsensitiveMap() {
- caseInsensitiveMap = new int[INITIAL_CHUNK_COUNT][][];
- for (int i=0; i<INITIAL_CHUNK_COUNT; i++) {
- caseInsensitiveMap[i] = new int[CHUNK_SIZE][];
- }
-
+ caseInsensitiveMap = new int[INITIAL_CHUNK_COUNT][CHUNK_SIZE][];
int lc, uc;
for (int i=0; i<0x10000; i++) {
lc = Character.toLowerCase(i);
@@ -100,8 +91,6 @@
set(i, map);
}
}
-
- mapBuilt = Boolean.TRUE;
}
private static int[] expandMap(int[] srcMap, int expandBy) {
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/Match.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/Match.java Wed Jul 05 21:02:29 2017 +0200
@@ -3,11 +3,12 @@
* DO NOT REMOVE OR ALTER!
*/
/*
- * Copyright 1999-2002,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/Op.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/Op.java Wed Jul 05 21:02:29 2017 +0200
@@ -3,11 +3,12 @@
* DO NOT REMOVE OR ALTER!
*/
/*
- * Copyright 1999-2002,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
@@ -20,7 +21,7 @@
package com.sun.org.apache.xerces.internal.impl.xpath.regex;
-import java.util.Vector;
+import java.util.ArrayList;
/**
* @xerces.internal
@@ -126,7 +127,7 @@
return op;
}
- int type;
+ final int type;
Op next = null;
protected Op(int type) {
@@ -158,7 +159,7 @@
// ================================================================
static class CharOp extends Op {
- int charData;
+ final int charData;
CharOp(int type, int data) {
super(type);
this.charData = data;
@@ -170,19 +171,19 @@
// ================================================================
static class UnionOp extends Op {
- Vector branches;
+ final ArrayList<Op> branches;
UnionOp(int type, int size) {
super(type);
- this.branches = new Vector(size);
+ this.branches = new ArrayList<>(size);
}
void addElement(Op op) {
- this.branches.addElement(op);
+ this.branches.add(op);
}
int size() {
return this.branches.size();
}
Op elementAt(int index) {
- return (Op)this.branches.elementAt(index);
+ return this.branches.get(index);
}
}
@@ -201,8 +202,8 @@
}
// ================================================================
static class ModifierOp extends ChildOp {
- int v1;
- int v2;
+ final int v1;
+ final int v2;
ModifierOp(int type, int v1, int v2) {
super(type);
this.v1 = v1;
@@ -217,7 +218,7 @@
}
// ================================================================
static class RangeOp extends Op {
- Token tok;
+ final Token tok;
RangeOp(int type, Token tok) {
super(type);
this.tok = tok;
@@ -228,7 +229,7 @@
}
// ================================================================
static class StringOp extends Op {
- String string;
+ final String string;
StringOp(int type, String literal) {
super(type);
this.string = literal;
@@ -239,10 +240,10 @@
}
// ================================================================
static class ConditionOp extends Op {
- int refNumber;
- Op condition;
- Op yes;
- Op no;
+ final int refNumber;
+ final Op condition;
+ final Op yes;
+ final Op no;
ConditionOp(int type, int refno, Op conditionflow, Op yesflow, Op noflow) {
super(type);
this.refNumber = refno;
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/ParseException.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/ParseException.java Wed Jul 05 21:02:29 2017 +0200
@@ -3,11 +3,12 @@
* DO NOT REMOVE OR ALTER!
*/
/*
- * Copyright 1999-2002,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
@@ -30,7 +31,7 @@
/** Serialization version. */
static final long serialVersionUID = -7012400318097691370L;
- int location;
+ final int location;
/*
public ParseException(String mes) {
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/ParserForXMLSchema.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/ParserForXMLSchema.java Wed Jul 05 21:02:29 2017 +0200
@@ -252,7 +252,7 @@
if (c == ']') throw this.ex("parser.cc.7", this.offset-2);
if (c == '-' && this.chardata != ']' && !firstloop) throw this.ex("parser.cc.8", this.offset-2); // if regex = '[-]' then invalid
}
- if (this.read() != T_CHAR || this.chardata != '-' || c == '-' && firstloop) { // Here is no '-'.
+ if (this.read() != T_CHAR || this.chardata != '-' || c == '-' && !wasDecoded && firstloop) { // Here is no '-'.
if (!this.isSet(RegularExpression.IGNORE_CASE) || c > 0xffff) {
tok.addRange(c, c);
}
@@ -382,17 +382,20 @@
ranges2.put("xml:isSpace", Token.complementRanges(tok));
tok = Token.createRange();
- setupRange(tok, DIGITS);
- setupRange(tok, DIGITS_INT);
+ setupRange(tok, DIGITS_INTS);
ranges.put("xml:isDigit", tok);
ranges2.put("xml:isDigit", Token.complementRanges(tok));
+ /*
+ * \w is defined by the XML Schema specification to be:
+ * [#x0000-#x10FFFF]-[\p{P}\p{Z}\p{C}] (all characters except the set of "punctuation", "separator" and "other" characters)
+ */
tok = Token.createRange();
- setupRange(tok, LETTERS);
- setupRange(tok, LETTERS_INT);
- tok.mergeRanges(ranges.get("xml:isDigit"));
- ranges.put("xml:isWord", tok);
- ranges2.put("xml:isWord", Token.complementRanges(tok));
+ tok.mergeRanges(Token.getRange("P", true));
+ tok.mergeRanges(Token.getRange("Z", true));
+ tok.mergeRanges(Token.getRange("C", true));
+ ranges2.put("xml:isWord", tok);
+ ranges.put("xml:isWord", Token.complementRanges(tok));
tok = Token.createRange();
setupRange(tok, NAMECHARS);
@@ -401,6 +404,7 @@
tok = Token.createRange();
setupRange(tok, LETTERS);
+ setupRange(tok, LETTERS_INT);
tok.addRange('_', '_');
tok.addRange(':', ':');
ranges.put("xml:isInitialNameChar", tok);
@@ -502,11 +506,12 @@
private static final int[] LETTERS_INT = {0x1d790, 0x1d7a8, 0x1d7aa, 0x1d7c9, 0x2fa1b, 0x2fa1d};
- private static final String DIGITS =
- "\u0030\u0039\u0660\u0669\u06F0\u06F9\u0966\u096F\u09E6\u09EF\u0A66\u0A6F\u0AE6\u0AEF"
- +"\u0B66\u0B6F\u0BE7\u0BEF\u0C66\u0C6F\u0CE6\u0CEF\u0D66\u0D6F\u0E50\u0E59\u0ED0\u0ED9"
- +"\u0F20\u0F29\u1040\u1049\u1369\u1371\u17E0\u17E9\u1810\u1819\uFF10\uFF19";
-
- private static final int[] DIGITS_INT = {0x1D7CE, 0x1D7FF};
-
+ private static final int[] DIGITS_INTS = {
+ 0x0030, 0x0039, 0x0660, 0x0669, 0x06F0, 0x06F9, 0x0966, 0x096F,
+ 0x09E6, 0x09EF, 0x0A66, 0x0A6F, 0x0AE6, 0x0AEF, 0x0B66, 0x0B6F,
+ 0x0BE7, 0x0BEF, 0x0C66, 0x0C6F, 0x0CE6, 0x0CEF, 0x0D66, 0x0D6F,
+ 0x0E50, 0x0E59, 0x0ED0, 0x0ED9, 0x0F20, 0x0F29, 0x1040, 0x1049,
+ 0x1369, 0x1371, 0x17E0, 0x17E9, 0x1810, 0x1819, 0xFF10, 0xFF19,
+ 0x1D7CE, 0x1D7FF
+ };
}
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/REUtil.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/REUtil.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,13 +1,13 @@
/*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
*/
/*
- * Copyright 1999-2002,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
@@ -110,27 +110,27 @@
}
static final String createOptionString(int options) {
- StringBuffer sb = new StringBuffer(9);
+ StringBuilder sb = new StringBuilder(9);
if ((options & RegularExpression.PROHIBIT_FIXED_STRING_OPTIMIZATION) != 0)
- sb.append((char)'F');
+ sb.append('F');
if ((options & RegularExpression.PROHIBIT_HEAD_CHARACTER_OPTIMIZATION) != 0)
- sb.append((char)'H');
+ sb.append('H');
if ((options & RegularExpression.XMLSCHEMA_MODE) != 0)
- sb.append((char)'X');
+ sb.append('X');
if ((options & RegularExpression.IGNORE_CASE) != 0)
- sb.append((char)'i');
+ sb.append('i');
if ((options & RegularExpression.MULTIPLE_LINES) != 0)
- sb.append((char)'m');
+ sb.append('m');
if ((options & RegularExpression.SINGLE_LINE) != 0)
- sb.append((char)'s');
+ sb.append('s');
if ((options & RegularExpression.USE_UNICODE_CATEGORY) != 0)
- sb.append((char)'u');
+ sb.append('u');
if ((options & RegularExpression.UNICODE_WORD_BOUNDARY) != 0)
- sb.append((char)'w');
+ sb.append('w');
if ((options & RegularExpression.EXTENDED_COMMENT) != 0)
- sb.append((char)'x');
+ sb.append('x');
if ((options & RegularExpression.SPECIAL_COMMA) != 0)
- sb.append((char)',');
+ sb.append(',');
return sb.toString().intern();
}
@@ -138,13 +138,19 @@
static String stripExtendedComment(String regex) {
int len = regex.length();
- StringBuffer buffer = new StringBuffer(len);
+ StringBuilder buffer = new StringBuilder(len);
int offset = 0;
+ int charClass = 0;
while (offset < len) {
int ch = regex.charAt(offset++);
// Skips a white space.
- if (ch == '\t' || ch == '\n' || ch == '\f' || ch == '\r' || ch == ' ')
+ if (ch == '\t' || ch == '\n' || ch == '\f' || ch == '\r' || ch == ' ') {
+ // if we are inside a character class, we keep the white space
+ if (charClass > 0) {
+ buffer.append((char)ch);
+ }
continue;
+ }
if (ch == '#') { // Skips chracters between '#' and a line end.
while (offset < len) {
@@ -163,12 +169,36 @@
buffer.append((char)next);
offset ++;
} else { // Other escaped character.
- buffer.append((char)'\\');
+ buffer.append('\\');
buffer.append((char)next);
offset ++;
}
- } else // As is.
+ }
+ else if (ch == '[') {
+ charClass++;
buffer.append((char)ch);
+ if (offset < len) {
+ next = regex.charAt(offset);
+ if (next == '[' || next ==']') {
+ buffer.append((char)next);
+ offset ++;
+ }
+ else if (next == '^' && offset + 1 < len) {
+ next = regex.charAt(offset + 1);
+ if (next == '[' || next ==']') {
+ buffer.append('^');
+ buffer.append((char)next);
+ offset += 2;
+ }
+ }
+ }
+ }
+ else {
+ if (charClass > 0 && ch == ']') {
+ --charClass;
+ }
+ buffer.append((char)ch);
+ }
}
return buffer.toString();
}
@@ -307,15 +337,15 @@
*/
public static String quoteMeta(String literal) {
int len = literal.length();
- StringBuffer buffer = null;
+ StringBuilder buffer = null;
for (int i = 0; i < len; i ++) {
int ch = literal.charAt(i);
if (".*+?{[()|\\^$".indexOf(ch) >= 0) {
if (buffer == null) {
- buffer = new StringBuffer(i+(len-i)*2);
+ buffer = new StringBuilder(i+(len-i)*2);
if (i > 0) buffer.append(literal.substring(0, i));
}
- buffer.append((char)'\\');
+ buffer.append('\\');
buffer.append((char)ch);
} else if (buffer != null)
buffer.append((char)ch);
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/RangeToken.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/RangeToken.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,6 +1,5 @@
/*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -43,7 +42,7 @@
this.setSorted(false);
}
- // for RANGE or NRANGE
+ // for RANGE or NRANGE
protected void addRange(int start, int end) {
this.icaseCache = null;
//System.err.println("Token#addRange(): "+start+" "+end);
@@ -560,7 +559,7 @@
sb.append(escapeCharInCharClass(this.ranges[i]));
} else {
sb.append(escapeCharInCharClass(this.ranges[i]));
- sb.append((char)'-');
+ sb.append('-');
sb.append(escapeCharInCharClass(this.ranges[i+1]));
}
}
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/RegexParser.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/RegexParser.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,13 +1,13 @@
/*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
*/
/*
- * Copyright 1999-2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
@@ -24,7 +24,7 @@
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
-import java.util.Vector;
+import java.util.ArrayList;
/**
* A Regular Expression Parser.
@@ -82,8 +82,7 @@
int parenOpened = 1;
int parennumber = 1;
boolean hasBackReferences;
- Vector references = null;
- int parenCount = 0;
+ ArrayList<ReferencePosition> references = null;
public RegexParser() {
this.setLocale(Locale.getDefault());
@@ -115,7 +114,7 @@
return (this.options & flag) == flag;
}
- synchronized Token parse(String regex, int options) throws ParseException {
+ Token parse(String regex, int options) throws ParseException {
this.options = options;
this.offset = 0;
this.setContext(S_NORMAL);
@@ -132,15 +131,16 @@
Token ret = this.parseRegex();
if (this.offset != this.regexlen)
throw ex("parser.parse.1", this.offset);
- if (parenCount < 0)
- throw ex("parser.factor.0", this.offset);
+ if (this.read() != T_EOF) {
+ throw ex("parser.parse.1", this.offset-1);
+ }
if (this.references != null) {
for (int i = 0; i < this.references.size(); i ++) {
- ReferencePosition position = (ReferencePosition)this.references.elementAt(i);
+ ReferencePosition position = this.references.get(i);
if (this.parennumber <= position.refNumber)
throw ex("parser.parse.2", position.position);
}
- this.references.removeAllElements();
+ this.references.clear();
}
return ret;
}
@@ -160,6 +160,7 @@
return this.nexttoken;
}
+ @SuppressWarnings("fallthrough")
final void next() {
if (this.offset >= this.regexlen) {
this.chardata = -1;
@@ -239,7 +240,6 @@
break;
case '(':
ret = T_LPAREN;
- parenCount++;
if (this.offset >= this.regexlen)
break;
if (this.regex.charAt(this.offset) != '?')
@@ -328,11 +328,10 @@
*/
Token parseTerm() throws ParseException {
int ch = this.read();
- Token tok = null;
if (ch == T_OR || ch == T_RPAREN || ch == T_EOF) {
- tok = Token.createEmpty();
+ return Token.createEmpty();
} else {
- tok = this.parseFactor();
+ Token tok = this.parseFactor();
Token concat = null;
while ((ch = this.read()) != T_OR && ch != T_RPAREN && ch != T_EOF) {
if (concat == null) {
@@ -343,11 +342,8 @@
concat.addChild(this.parseFactor());
//tok = Token.createConcat(tok, this.parseFactor());
}
+ return tok;
}
- if (ch == T_RPAREN) {
- parenCount--;
- }
- return tok;
}
// ----------------------------------------------------------------
@@ -482,7 +478,7 @@
while (this.offset + 1 < this.regexlen) {
ch = this.regex.charAt(this.offset + 1);
- if ('1' <= ch && ch <= '9') {
+ if ('0' <= ch && ch <= '9') {
refno = (refno * 10) + (ch - '0');
if (refno < this.parennumber) {
finalRefno= refno;
@@ -498,8 +494,8 @@
}
this.hasBackReferences = true;
- if (this.references == null) this.references = new Vector();
- this.references.addElement(new ReferencePosition(finalRefno, this.offset));
+ if (this.references == null) this.references = new ArrayList<>();
+ this.references.add(new ReferencePosition(finalRefno, this.offset));
this.offset ++;
if (this.regex.charAt(this.offset) != ')') throw ex("parser.factor.1", this.offset);
this.offset ++;
@@ -615,7 +611,7 @@
while (this.offset < this.regexlen) {
final int ch = this.regex.charAt(this.offset);
- if ('1' <= ch && ch <= '9') {
+ if ('0' <= ch && ch <= '9') {
refnum = (refnum * 10) + (ch - '0');
if (refnum < this.parennumber) {
++this.offset;
@@ -633,8 +629,8 @@
Token tok = Token.createBackReference(finalRefnum);
this.hasBackReferences = true;
- if (this.references == null) this.references = new Vector();
- this.references.addElement(new ReferencePosition(finalRefnum, this.offset-2));
+ if (this.references == null) this.references = new ArrayList<>();
+ this.references.add(new ReferencePosition(finalRefnum, this.offset-2));
this.next();
return tok;
}
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/RegularExpression.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/RegularExpression.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,13 +1,13 @@
/*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
*/
/*
- * Copyright 1999-2002,2004,2005 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
@@ -1041,9 +1041,10 @@
/**
* @return -1 when not match; offset of the end of matched string when match.
*/
+ @SuppressWarnings("fallthrough")
private int match(Context con, Op op, int offset, int dx, int opts) {
final ExpressionTarget target = con.target;
- final Stack opStack = new Stack();
+ final Stack<Op> opStack = new Stack<>();
final IntStack dataStack = new IntStack();
final boolean isSetIgnoreCase = isSet(opts, IGNORE_CASE);
int retValue = -1;
@@ -1322,7 +1323,7 @@
return retValue;
}
- op = (Op) opStack.pop();
+ op = opStack.pop();
offset = dataStack.pop();
switch (op.type) {
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/Token.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xpath/regex/Token.java Wed Jul 05 21:02:29 2017 +0200
@@ -859,7 +859,7 @@
buffer.append("Is");
if (n.indexOf(' ') >= 0) {
for (int ci = 0; ci < n.length(); ci ++)
- if (n.charAt(ci) != ' ') buffer.append((char)n.charAt(ci));
+ if (n.charAt(ci) != ' ') buffer.append(n.charAt(ci));
}
else {
buffer.append(n);
@@ -995,8 +995,8 @@
}
private static void setAlias(String newName, String name, boolean positive) {
- Token t1 = (Token)Token.categories.get(name);
- Token t2 = (Token)Token.categories2.get(name);
+ Token t1 = Token.categories.get(name);
+ Token t2 = Token.categories2.get(name);
if (positive) {
Token.categories.put(newName, t1);
Token.categories2.put(newName, t2);
@@ -1525,7 +1525,7 @@
this.children.stream().forEach((children1) -> {
sb.append((children1).toString(options));
});
- ret = new String(sb);
+ ret = sb.toString();
}
return ret;
}
@@ -1538,10 +1538,10 @@
StringBuilder sb = new StringBuilder();
sb.append((this.children.get(0)).toString(options));
for (int i = 1; i < this.children.size(); i ++) {
- sb.append((char)'|');
+ sb.append('|');
sb.append((this.children.get(i)).toString(options));
}
- ret = new String(sb);
+ ret = sb.toString();
}
return ret;
}
@@ -1557,7 +1557,7 @@
ObjectOutputStream.PutField pf = out.putFields();
pf.put("children", vChildren);
out.writeFields();
- }
+ }
@SuppressWarnings("unchecked")
private void readObject(ObjectInputStream in)
--- a/jaxp/test/TEST.ROOT Fri Nov 20 15:40:23 2015 -0800
+++ b/jaxp/test/TEST.ROOT Wed Jul 05 21:02:29 2017 +0200
@@ -18,4 +18,4 @@
groups=TEST.groups
# Minimum jtreg version
-requiredVersion=4.1 b11
+requiredVersion=4.1 b12
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/validation/tck/RegexWord.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package validation.tck;
+
+import java.io.IOException;
+import javax.xml.XMLConstants;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.validation.Validator;
+import org.testng.annotations.Test;
+import org.xml.sax.SAXException;
+
+/*
+ * @bug 8142900
+ * @summary Verifies that all characters except the set of "punctuation",
+ * "separator" and "other" characters are accepted by \w [#x0000-#x10FFFF]-[\p{P}\p{Z}\p{C}]
+ * @author Joe Wang
+ */
+public class RegexWord {
+ static final String SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
+ static final String SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
+
+ /*
+ The original reZ003v.xml contains a full list of word characters that \w should accept.
+ However, U+2308..U+230B were changed from Sm to either Ps or Pe in Unicode 7.0.
+ They are therefore excluded from the test.
+
+ The test throws an Exception (and fails) if it fails to recognize any of characters.
+ */
+ @Test
+ public void test() throws SAXException, IOException {
+ SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+ Schema schema = schemaFactory.newSchema(new StreamSource(RegexWord.class.getResourceAsStream("reZ003.xsd")));
+ Validator validator = schema.newValidator();
+
+ validator.validate(new StreamSource(RegexWord.class.getResourceAsStream("reZ003vExc23082309.xml")));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/validation/tck/reZ003.xsd Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+<xs:element name="doc">
+<xs:complexType>
+<xs:sequence>
+<xs:element name="value" maxOccurs='unbounded'>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[\w]"/>
+ </xs:restriction>
+ </xs:simpleType>
+</xs:element>
+</xs:sequence>
+</xs:complexType>
+</xs:element>
+</xs:schema>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/validation/tck/reZ003vExc23082309.xml Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,9273 @@
+<doc>
+<value>2</value>
+<value>3</value>
+<value>4</value>
+<value>5</value>
+<value>6</value>
+<value>7</value>
+<value>8</value>
+<value>9</value>
+<value>A</value>
+<value>B</value>
+<value>C</value>
+<value>D</value>
+<value>E</value>
+<value>F</value>
+<value>G</value>
+<value>H</value>
+<value>I</value>
+<value>P</value>
+<value>Q</value>
+<value>R</value>
+<value>S</value>
+<value>T</value>
+<value>U</value>
+<value>V</value>
+<value>W</value>
+<value>X</value>
+<value>Y</value>
+<value>`</value>
+<value>a</value>
+<value>b</value>
+<value>c</value>
+<value>d</value>
+<value>e</value>
+<value>f</value>
+<value>g</value>
+<value>h</value>
+<value>i</value>
+<value>p</value>
+<value>q</value>
+<value>r</value>
+<value>s</value>
+<value>t</value>
+<value>u</value>
+<value>v</value>
+<value>w</value>
+<value>x</value>
+<value>y</value>
+<value>Ā</value>
+<value>ā</value>
+<value>Ă</value>
+<value>ă</value>
+<value>Ą</value>
+<value>ą</value>
+<value>Ć</value>
+<value>ć</value>
+<value>Ĉ</value>
+<value>ĉ</value>
+<value>Đ</value>
+<value>đ</value>
+<value>Ē</value>
+<value>ē</value>
+<value>Ĕ</value>
+<value>ĕ</value>
+<value>Ė</value>
+<value>ė</value>
+<value>Ę</value>
+<value>ę</value>
+<value>Ġ</value>
+<value>ġ</value>
+<value>Ģ</value>
+<value>ģ</value>
+<value>Ĥ</value>
+<value>ĥ</value>
+<value>Ħ</value>
+<value>ħ</value>
+<value>Ĩ</value>
+<value>ĩ</value>
+<value>İ</value>
+<value>ı</value>
+<value>IJ</value>
+<value>ij</value>
+<value>Ĵ</value>
+<value>ĵ</value>
+<value>Ķ</value>
+<value>ķ</value>
+<value>ĸ</value>
+<value>Ĺ</value>
+<value>ŀ</value>
+<value>Ł</value>
+<value>ł</value>
+<value>Ń</value>
+<value>ń</value>
+<value>Ņ</value>
+<value>ņ</value>
+<value>Ň</value>
+<value>ň</value>
+<value>ʼn</value>
+<value>Ő</value>
+<value>ő</value>
+<value>Œ</value>
+<value>œ</value>
+<value>Ŕ</value>
+<value>ŕ</value>
+<value>Ŗ</value>
+<value>ŗ</value>
+<value>Ř</value>
+<value>ř</value>
+<value>Š</value>
+<value>š</value>
+<value>Ţ</value>
+<value>ţ</value>
+<value>Ť</value>
+<value>ť</value>
+<value>Ŧ</value>
+<value>ŧ</value>
+<value>Ũ</value>
+<value>ũ</value>
+<value>Ű</value>
+<value>ű</value>
+<value>Ų</value>
+<value>ų</value>
+<value>Ŵ</value>
+<value>ŵ</value>
+<value>Ŷ</value>
+<value>ŷ</value>
+<value>Ÿ</value>
+<value>Ź</value>
+<value>ƀ</value>
+<value>Ɓ</value>
+<value>Ƃ</value>
+<value>ƃ</value>
+<value>Ƅ</value>
+<value>ƅ</value>
+<value>Ɔ</value>
+<value>Ƈ</value>
+<value>ƈ</value>
+<value>Ɖ</value>
+<value>Ɛ</value>
+<value>Ƒ</value>
+<value>ƒ</value>
+<value>Ɠ</value>
+<value>Ɣ</value>
+<value>ƕ</value>
+<value>Ɩ</value>
+<value>Ɨ</value>
+<value>Ƙ</value>
+<value>ƙ</value>
+<value>Ȁ</value>
+<value>ȁ</value>
+<value>Ȃ</value>
+<value>ȃ</value>
+<value>Ȅ</value>
+<value>ȅ</value>
+<value>Ȇ</value>
+<value>ȇ</value>
+<value>Ȉ</value>
+<value>ȉ</value>
+<value>Ȑ</value>
+<value>ȑ</value>
+<value>Ȓ</value>
+<value>ȓ</value>
+<value>Ȕ</value>
+<value>ȕ</value>
+<value>Ȗ</value>
+<value>ȗ</value>
+<value>Ș</value>
+<value>ș</value>
+<value>Ƞ</value>
+<value>Ȣ</value>
+<value>ȣ</value>
+<value>Ȥ</value>
+<value>ȥ</value>
+<value>Ȧ</value>
+<value>ȧ</value>
+<value>Ȩ</value>
+<value>ȩ</value>
+<value>Ȱ</value>
+<value>ȱ</value>
+<value>Ȳ</value>
+<value>ȳ</value>
+<value>ɐ</value>
+<value>ɑ</value>
+<value>ɒ</value>
+<value>ɓ</value>
+<value>ɔ</value>
+<value>ɕ</value>
+<value>ɖ</value>
+<value>ɗ</value>
+<value>ɘ</value>
+<value>ə</value>
+<value>ɠ</value>
+<value>ɡ</value>
+<value>ɢ</value>
+<value>ɣ</value>
+<value>ɤ</value>
+<value>ɥ</value>
+<value>ɦ</value>
+<value>ɧ</value>
+<value>ɨ</value>
+<value>ɩ</value>
+<value>ɰ</value>
+<value>ɱ</value>
+<value>ɲ</value>
+<value>ɳ</value>
+<value>ɴ</value>
+<value>ɵ</value>
+<value>ɶ</value>
+<value>ɷ</value>
+<value>ɸ</value>
+<value>ɹ</value>
+<value>ʀ</value>
+<value>ʁ</value>
+<value>ʂ</value>
+<value>ʃ</value>
+<value>ʄ</value>
+<value>ʅ</value>
+<value>ʆ</value>
+<value>ʇ</value>
+<value>ʈ</value>
+<value>ʉ</value>
+<value>ʐ</value>
+<value>ʑ</value>
+<value>ʒ</value>
+<value>ʓ</value>
+<value>ʔ</value>
+<value>ʕ</value>
+<value>ʖ</value>
+<value>ʗ</value>
+<value>ʘ</value>
+<value>ʙ</value>
+<value>̀</value>
+<value>́</value>
+<value>̂</value>
+<value>̃</value>
+<value>̄</value>
+<value>̅</value>
+<value>̆</value>
+<value>̇</value>
+<value>̈</value>
+<value>̉</value>
+<value>̐</value>
+<value>̑</value>
+<value>̒</value>
+<value>̓</value>
+<value>̔</value>
+<value>̕</value>
+<value>̖</value>
+<value>̗</value>
+<value>̘</value>
+<value>̙</value>
+<value>̠</value>
+<value>̡</value>
+<value>̢</value>
+<value>̣</value>
+<value>̤</value>
+<value>̥</value>
+<value>̦</value>
+<value>̧</value>
+<value>̨</value>
+<value>̩</value>
+<value>̰</value>
+<value>̱</value>
+<value>̲</value>
+<value>̳</value>
+<value>̴</value>
+<value>̵</value>
+<value>̶</value>
+<value>̷</value>
+<value≯</value>
+<value>̹</value>
+<value>̀</value>
+<value>́</value>
+<value>͂</value>
+<value>̓</value>
+<value>̈́</value>
+<value>ͅ</value>
+<value>͆</value>
+<value>͇</value>
+<value>͈</value>
+<value>͉</value>
+<value>͠</value>
+<value>͡</value>
+<value>͢</value>
+<value>ͣ</value>
+<value>ͤ</value>
+<value>ͥ</value>
+<value>ͦ</value>
+<value>ͧ</value>
+<value>ͨ</value>
+<value>ͩ</value>
+<value>ʹ</value>
+<value>͵</value>
+<value>΄</value>
+<value>΅</value>
+<value>Ά</value>
+<value>Έ</value>
+<value>Ή</value>
+<value>ΐ</value>
+<value>Α</value>
+<value>Β</value>
+<value>Γ</value>
+<value>Δ</value>
+<value>Ε</value>
+<value>Ζ</value>
+<value>Η</value>
+<value>Θ</value>
+<value>Ι</value>
+<value>Ѐ</value>
+<value>Ё</value>
+<value>Ђ</value>
+<value>Ѓ</value>
+<value>Є</value>
+<value>Ѕ</value>
+<value>І</value>
+<value>Ї</value>
+<value>Ј</value>
+<value>Љ</value>
+<value>А</value>
+<value>Б</value>
+<value>В</value>
+<value>Г</value>
+<value>Д</value>
+<value>Е</value>
+<value>Ж</value>
+<value>З</value>
+<value>И</value>
+<value>Й</value>
+<value>Р</value>
+<value>С</value>
+<value>Т</value>
+<value>У</value>
+<value>Ф</value>
+<value>Х</value>
+<value>Ц</value>
+<value>Ч</value>
+<value>Ш</value>
+<value>Щ</value>
+<value>а</value>
+<value>б</value>
+<value>в</value>
+<value>г</value>
+<value>д</value>
+<value>е</value>
+<value>ж</value>
+<value>з</value>
+<value>и</value>
+<value>й</value>
+<value>р</value>
+<value>с</value>
+<value>т</value>
+<value>у</value>
+<value>ф</value>
+<value>х</value>
+<value>ц</value>
+<value>ч</value>
+<value>ш</value>
+<value>щ</value>
+<value>ѐ</value>
+<value>ё</value>
+<value>ђ</value>
+<value>ѓ</value>
+<value>є</value>
+<value>ѕ</value>
+<value>і</value>
+<value>ї</value>
+<value>ј</value>
+<value>љ</value>
+<value>Ѡ</value>
+<value>ѡ</value>
+<value>Ѣ</value>
+<value>ѣ</value>
+<value>Ѥ</value>
+<value>ѥ</value>
+<value>Ѧ</value>
+<value>ѧ</value>
+<value>Ѩ</value>
+<value>ѩ</value>
+<value>Ѱ</value>
+<value>ѱ</value>
+<value>Ѳ</value>
+<value>ѳ</value>
+<value>Ѵ</value>
+<value>ѵ</value>
+<value>Ѷ</value>
+<value>ѷ</value>
+<value>Ѹ</value>
+<value>ѹ</value>
+<value>Ҁ</value>
+<value>ҁ</value>
+<value>҂</value>
+<value>҃</value>
+<value>҄</value>
+<value>҅</value>
+<value>҆</value>
+<value>҈</value>
+<value>҉</value>
+<value>Ґ</value>
+<value>ґ</value>
+<value>Ғ</value>
+<value>ғ</value>
+<value>Ҕ</value>
+<value>ҕ</value>
+<value>Җ</value>
+<value>җ</value>
+<value>Ҙ</value>
+<value>ҙ</value>
+<value>Ԁ</value>
+<value>ԁ</value>
+<value>Ԃ</value>
+<value>ԃ</value>
+<value>Ԅ</value>
+<value>ԅ</value>
+<value>Ԇ</value>
+<value>ԇ</value>
+<value>Ԉ</value>
+<value>ԉ</value>
+<value>Ա</value>
+<value>Բ</value>
+<value>Գ</value>
+<value>Դ</value>
+<value>Ե</value>
+<value>Զ</value>
+<value>Է</value>
+<value>Ը</value>
+<value>Թ</value>
+<value>Հ</value>
+<value>Ձ</value>
+<value>Ղ</value>
+<value>Ճ</value>
+<value>Մ</value>
+<value>Յ</value>
+<value>Ն</value>
+<value>Շ</value>
+<value>Ո</value>
+<value>Չ</value>
+<value>Ր</value>
+<value>Ց</value>
+<value>Ւ</value>
+<value>Փ</value>
+<value>Ք</value>
+<value>Օ</value>
+<value>Ֆ</value>
+<value>ՙ</value>
+<value>ա</value>
+<value>բ</value>
+<value>գ</value>
+<value>դ</value>
+<value>ե</value>
+<value>զ</value>
+<value>է</value>
+<value>ը</value>
+<value>թ</value>
+<value>հ</value>
+<value>ձ</value>
+<value>ղ</value>
+<value>ճ</value>
+<value>մ</value>
+<value>յ</value>
+<value>ն</value>
+<value>շ</value>
+<value>ո</value>
+<value>չ</value>
+<value>ր</value>
+<value>ց</value>
+<value>ւ</value>
+<value>փ</value>
+<value>ք</value>
+<value>օ</value>
+<value>ֆ</value>
+<value>և</value>
+<value>֑</value>
+<value>֒</value>
+<value>֓</value>
+<value>֔</value>
+<value>֕</value>
+<value>֖</value>
+<value>֗</value>
+<value>֘</value>
+<value>֙</value>
+<value>ء</value>
+<value>آ</value>
+<value>أ</value>
+<value>ؤ</value>
+<value>إ</value>
+<value>ئ</value>
+<value>ا</value>
+<value>ب</value>
+<value>ة</value>
+<value>ذ</value>
+<value>ر</value>
+<value>ز</value>
+<value>س</value>
+<value>ش</value>
+<value>ص</value>
+<value>ض</value>
+<value>ط</value>
+<value>ظ</value>
+<value>ع</value>
+<value>ـ</value>
+<value>ف</value>
+<value>ق</value>
+<value>ك</value>
+<value>ل</value>
+<value>م</value>
+<value>ن</value>
+<value>ه</value>
+<value>و</value>
+<value>ى</value>
+<value>ِ</value>
+<value>ّ</value>
+<value>ْ</value>
+<value>ٓ</value>
+<value>ٔ</value>
+<value>ٕ</value>
+<value>٠</value>
+<value>١</value>
+<value>٢</value>
+<value>٣</value>
+<value>٤</value>
+<value>٥</value>
+<value>٦</value>
+<value>٧</value>
+<value>٨</value>
+<value>٩</value>
+<value>ٰ</value>
+<value>ٱ</value>
+<value>ٲ</value>
+<value>ٳ</value>
+<value>ٴ</value>
+<value>ٵ</value>
+<value>ٶ</value>
+<value>ٷ</value>
+<value>ٸ</value>
+<value>ٹ</value>
+<value>ڀ</value>
+<value>ځ</value>
+<value>ڂ</value>
+<value>ڃ</value>
+<value>ڄ</value>
+<value>څ</value>
+<value>چ</value>
+<value>ڇ</value>
+<value>ڈ</value>
+<value>ډ</value>
+<value>ڐ</value>
+<value>ڑ</value>
+<value>ڒ</value>
+<value>ړ</value>
+<value>ڔ</value>
+<value>ڕ</value>
+<value>ږ</value>
+<value>ڗ</value>
+<value>ژ</value>
+<value>ڙ</value>
+<value>ܐ</value>
+<value>ܑ</value>
+<value>ܒ</value>
+<value>ܓ</value>
+<value>ܔ</value>
+<value>ܕ</value>
+<value>ܖ</value>
+<value>ܗ</value>
+<value>ܘ</value>
+<value>ܙ</value>
+<value>ܠ</value>
+<value>ܡ</value>
+<value>ܢ</value>
+<value>ܣ</value>
+<value>ܤ</value>
+<value>ܥ</value>
+<value>ܦ</value>
+<value>ܧ</value>
+<value>ܨ</value>
+<value>ܩ</value>
+<value>ܰ</value>
+<value>ܱ</value>
+<value>ܲ</value>
+<value>ܳ</value>
+<value>ܴ</value>
+<value>ܵ</value>
+<value>ܶ</value>
+<value>ܷ</value>
+<value>ܸ</value>
+<value>ܹ</value>
+<value>݀</value>
+<value>݁</value>
+<value>݂</value>
+<value>݃</value>
+<value>݄</value>
+<value>݅</value>
+<value>݆</value>
+<value>݇</value>
+<value>݈</value>
+<value>݉</value>
+<value>ހ</value>
+<value>ށ</value>
+<value>ނ</value>
+<value>ރ</value>
+<value>ބ</value>
+<value>ޅ</value>
+<value>ކ</value>
+<value>އ</value>
+<value>ވ</value>
+<value>މ</value>
+<value>ސ</value>
+<value>ޑ</value>
+<value>ޒ</value>
+<value>ޓ</value>
+<value>ޔ</value>
+<value>ޕ</value>
+<value>ޖ</value>
+<value>ޗ</value>
+<value>ޘ</value>
+<value>ޙ</value>
+<value>ँ</value>
+<value>ं</value>
+<value>ः</value>
+<value>अ</value>
+<value>आ</value>
+<value>इ</value>
+<value>ई</value>
+<value>उ</value>
+<value>ऐ</value>
+<value>ऑ</value>
+<value>ऒ</value>
+<value>ओ</value>
+<value>औ</value>
+<value>क</value>
+<value>ख</value>
+<value>ग</value>
+<value>घ</value>
+<value>ङ</value>
+<value>ठ</value>
+<value>ड</value>
+<value>ढ</value>
+<value>ण</value>
+<value>त</value>
+<value>थ</value>
+<value>द</value>
+<value>ध</value>
+<value>न</value>
+<value>ऩ</value>
+<value>र</value>
+<value>ऱ</value>
+<value>ल</value>
+<value>ळ</value>
+<value>ऴ</value>
+<value>व</value>
+<value>श</value>
+<value>ष</value>
+<value>स</value>
+<value>ह</value>
+<value>ी</value>
+<value>ु</value>
+<value>ू</value>
+<value>ृ</value>
+<value>ॄ</value>
+<value>ॅ</value>
+<value>ॆ</value>
+<value>े</value>
+<value>ै</value>
+<value>ॉ</value>
+<value>ॐ</value>
+<value>॑</value>
+<value>॒</value>
+<value>॓</value>
+<value>॔</value>
+<value>क़</value>
+<value>ख़</value>
+<value>ॠ</value>
+<value>ॡ</value>
+<value>ॢ</value>
+<value>ॣ</value>
+<value>०</value>
+<value>१</value>
+<value>२</value>
+<value>३</value>
+<value>ঁ</value>
+<value>ং</value>
+<value>ঃ</value>
+<value>অ</value>
+<value>আ</value>
+<value>ই</value>
+<value>ঈ</value>
+<value>উ</value>
+<value>ঐ</value>
+<value>ও</value>
+<value>ঔ</value>
+<value>ক</value>
+<value>খ</value>
+<value>গ</value>
+<value>ঘ</value>
+<value>ঙ</value>
+<value>က</value>
+<value>ခ</value>
+<value>ဂ</value>
+<value>ဃ</value>
+<value>င</value>
+<value>စ</value>
+<value>ဆ</value>
+<value>ဇ</value>
+<value>ဈ</value>
+<value>ဉ</value>
+<value>တ</value>
+<value>ထ</value>
+<value>ဒ</value>
+<value>ဓ</value>
+<value>န</value>
+<value>ပ</value>
+<value>ဖ</value>
+<value>ဗ</value>
+<value>ဘ</value>
+<value>မ</value>
+<value>ဠ</value>
+<value>အ</value>
+<value>ဣ</value>
+<value>ဤ</value>
+<value>ဥ</value>
+<value>ဦ</value>
+<value>ဧ</value>
+<value>ဩ</value>
+<value>ူ</value>
+<value>ေ</value>
+<value>ဲ</value>
+<value>ံ</value>
+<value>့</value>
+<value>း</value>
+<value>္</value>
+<value>၀</value>
+<value>၁</value>
+<value>၂</value>
+<value>၃</value>
+<value>၄</value>
+<value>၅</value>
+<value>၆</value>
+<value>၇</value>
+<value>၈</value>
+<value>၉</value>
+<value>ၐ</value>
+<value>ၑ</value>
+<value>ၒ</value>
+<value>ၓ</value>
+<value>ၔ</value>
+<value>ၕ</value>
+<value>ၖ</value>
+<value>ၗ</value>
+<value>ၘ</value>
+<value>ၙ</value>
+<value>ᄀ</value>
+<value>ᄁ</value>
+<value>ᄂ</value>
+<value>ᄃ</value>
+<value>ᄄ</value>
+<value>ᄅ</value>
+<value>ᄆ</value>
+<value>ᄇ</value>
+<value>ᄈ</value>
+<value>ᄉ</value>
+<value>ᄐ</value>
+<value>ᄑ</value>
+<value>ᄒ</value>
+<value>ᄓ</value>
+<value>ᄔ</value>
+<value>ᄕ</value>
+<value>ᄖ</value>
+<value>ᄗ</value>
+<value>ᄘ</value>
+<value>ᄙ</value>
+<value>ᄠ</value>
+<value>ᄡ</value>
+<value>ᄢ</value>
+<value>ᄣ</value>
+<value>ᄤ</value>
+<value>ᄥ</value>
+<value>ᄦ</value>
+<value>ᄧ</value>
+<value>ᄨ</value>
+<value>ᄩ</value>
+<value>ᄰ</value>
+<value>ᄱ</value>
+<value>ᄲ</value>
+<value>ᄳ</value>
+<value>ᄴ</value>
+<value>ᄵ</value>
+<value>ᄶ</value>
+<value>ᄷ</value>
+<value>ᄸ</value>
+<value>ᄹ</value>
+<value>ᅀ</value>
+<value>ᅁ</value>
+<value>ᅂ</value>
+<value>ᅃ</value>
+<value>ᅄ</value>
+<value>ᅅ</value>
+<value>ᅆ</value>
+<value>ᅇ</value>
+<value>ᅈ</value>
+<value>ᅉ</value>
+<value>ᅐ</value>
+<value>ᅑ</value>
+<value>ᅒ</value>
+<value>ᅓ</value>
+<value>ᅔ</value>
+<value>ᅕ</value>
+<value>ᅖ</value>
+<value>ᅗ</value>
+<value>ᅘ</value>
+<value>ᅙ</value>
+<value>ᅠ</value>
+<value>ᅡ</value>
+<value>ᅢ</value>
+<value>ᅣ</value>
+<value>ᅤ</value>
+<value>ᅥ</value>
+<value>ᅦ</value>
+<value>ᅧ</value>
+<value>ᅨ</value>
+<value>ᅩ</value>
+<value>ᅰ</value>
+<value>ᅱ</value>
+<value>ᅲ</value>
+<value>ᅳ</value>
+<value>ᅴ</value>
+<value>ᅵ</value>
+<value>ᅶ</value>
+<value>ᅷ</value>
+<value>ᅸ</value>
+<value>ᅹ</value>
+<value>ᆀ</value>
+<value>ᆁ</value>
+<value>ᆂ</value>
+<value>ᆃ</value>
+<value>ᆄ</value>
+<value>ᆅ</value>
+<value>ᆆ</value>
+<value>ᆇ</value>
+<value>ᆈ</value>
+<value>ᆉ</value>
+<value>ᆐ</value>
+<value>ᆑ</value>
+<value>ᆒ</value>
+<value>ᆓ</value>
+<value>ᆔ</value>
+<value>ᆕ</value>
+<value>ᆖ</value>
+<value>ᆗ</value>
+<value>ᆘ</value>
+<value>ᆙ</value>
+<value>ሀ</value>
+<value>ሁ</value>
+<value>ሂ</value>
+<value>ሃ</value>
+<value>ሄ</value>
+<value>ህ</value>
+<value>ሆ</value>
+<value>ለ</value>
+<value>ሉ</value>
+<value>ሐ</value>
+<value>ሑ</value>
+<value>ሒ</value>
+<value>ሓ</value>
+<value>ሔ</value>
+<value>ሕ</value>
+<value>ሖ</value>
+<value>ሗ</value>
+<value>መ</value>
+<value>ሙ</value>
+<value>ሠ</value>
+<value>ሡ</value>
+<value>ሢ</value>
+<value>ሣ</value>
+<value>ሤ</value>
+<value>ሥ</value>
+<value>ሦ</value>
+<value>ሧ</value>
+<value>ረ</value>
+<value>ሩ</value>
+<value>ሰ</value>
+<value>ሱ</value>
+<value>ሲ</value>
+<value>ሳ</value>
+<value>ሴ</value>
+<value>ስ</value>
+<value>ሶ</value>
+<value>ሷ</value>
+<value>ሸ</value>
+<value>ሹ</value>
+<value>ቀ</value>
+<value>ቁ</value>
+<value>ቂ</value>
+<value>ቃ</value>
+<value>ቄ</value>
+<value>ቅ</value>
+<value>ቆ</value>
+<value>ቈ</value>
+<value>ቐ</value>
+<value>ቑ</value>
+<value>ቒ</value>
+<value>ቓ</value>
+<value>ቔ</value>
+<value>ቕ</value>
+<value>ቖ</value>
+<value>ቘ</value>
+<value>በ</value>
+<value>ቡ</value>
+<value>ቢ</value>
+<value>ባ</value>
+<value>ቤ</value>
+<value>ብ</value>
+<value>ቦ</value>
+<value>ቧ</value>
+<value>ቨ</value>
+<value>ቩ</value>
+<value>ተ</value>
+<value>ቱ</value>
+<value>ቲ</value>
+<value>ታ</value>
+<value>ቴ</value>
+<value>ት</value>
+<value>ቶ</value>
+<value>ቷ</value>
+<value>ቸ</value>
+<value>ቹ</value>
+<value>ኀ</value>
+<value>ኁ</value>
+<value>ኂ</value>
+<value>ኃ</value>
+<value>ኄ</value>
+<value>ኅ</value>
+<value>ኆ</value>
+<value>ኈ</value>
+<value>ነ</value>
+<value>ኑ</value>
+<value>ኒ</value>
+<value>ና</value>
+<value>ኔ</value>
+<value>ን</value>
+<value>ኖ</value>
+<value>ኗ</value>
+<value>ኘ</value>
+<value>ኙ</value>
+<value>ጀ</value>
+<value>ጁ</value>
+<value>ጂ</value>
+<value>ጃ</value>
+<value>ጄ</value>
+<value>ጅ</value>
+<value>ጆ</value>
+<value>ጇ</value>
+<value>ገ</value>
+<value>ጉ</value>
+<value>ጐ</value>
+<value>ጒ</value>
+<value>ጓ</value>
+<value>ጔ</value>
+<value>ጕ</value>
+<value>ጘ</value>
+<value>ጙ</value>
+<value>ጠ</value>
+<value>ጡ</value>
+<value>ጢ</value>
+<value>ጣ</value>
+<value>ጤ</value>
+<value>ጥ</value>
+<value>ጦ</value>
+<value>ጧ</value>
+<value>ጨ</value>
+<value>ጩ</value>
+<value>ጰ</value>
+<value>ጱ</value>
+<value>ጲ</value>
+<value>ጳ</value>
+<value>ጴ</value>
+<value>ጵ</value>
+<value>ጶ</value>
+<value>ጷ</value>
+<value>ጸ</value>
+<value>ጹ</value>
+<value>ፀ</value>
+<value>ፁ</value>
+<value>ፂ</value>
+<value>ፃ</value>
+<value>ፄ</value>
+<value>ፅ</value>
+<value>ፆ</value>
+<value>ፈ</value>
+<value>ፉ</value>
+<value>ፐ</value>
+<value>ፑ</value>
+<value>ፒ</value>
+<value>ፓ</value>
+<value>ፔ</value>
+<value>ፕ</value>
+<value>ፖ</value>
+<value>ፗ</value>
+<value>ፘ</value>
+<value>ፙ</value>
+<value>፩</value>
+<value>፰</value>
+<value>፱</value>
+<value>፲</value>
+<value>፳</value>
+<value>፴</value>
+<value>፵</value>
+<value>፶</value>
+<value>፷</value>
+<value>፸</value>
+<value>፹</value>
+<value>ᐁ</value>
+<value>ᐂ</value>
+<value>ᐃ</value>
+<value>ᐄ</value>
+<value>ᐅ</value>
+<value>ᐆ</value>
+<value>ᐇ</value>
+<value>ᐈ</value>
+<value>ᐉ</value>
+<value>ᐐ</value>
+<value>ᐑ</value>
+<value>ᐒ</value>
+<value>ᐓ</value>
+<value>ᐔ</value>
+<value>ᐕ</value>
+<value>ᐖ</value>
+<value>ᐗ</value>
+<value>ᐘ</value>
+<value>ᐙ</value>
+<value>ᐠ</value>
+<value>ᐡ</value>
+<value>ᐢ</value>
+<value>ᐣ</value>
+<value>ᐤ</value>
+<value>ᐥ</value>
+<value>ᐦ</value>
+<value>ᐧ</value>
+<value>ᐨ</value>
+<value>ᐩ</value>
+<value>ᐰ</value>
+<value>ᐱ</value>
+<value>ᐲ</value>
+<value>ᐳ</value>
+<value>ᐴ</value>
+<value>ᐵ</value>
+<value>ᐶ</value>
+<value>ᐷ</value>
+<value>ᐸ</value>
+<value>ᐹ</value>
+<value>ᑀ</value>
+<value>ᑁ</value>
+<value>ᑂ</value>
+<value>ᑃ</value>
+<value>ᑄ</value>
+<value>ᑅ</value>
+<value>ᑆ</value>
+<value>ᑇ</value>
+<value>ᑈ</value>
+<value>ᑉ</value>
+<value>ᑐ</value>
+<value>ᑑ</value>
+<value>ᑒ</value>
+<value>ᑓ</value>
+<value>ᑔ</value>
+<value>ᑕ</value>
+<value>ᑖ</value>
+<value>ᑗ</value>
+<value>ᑘ</value>
+<value>ᑙ</value>
+<value>ᑠ</value>
+<value>ᑡ</value>
+<value>ᑢ</value>
+<value>ᑣ</value>
+<value>ᑤ</value>
+<value>ᑥ</value>
+<value>ᑦ</value>
+<value>ᑧ</value>
+<value>ᑨ</value>
+<value>ᑩ</value>
+<value>ᑰ</value>
+<value>ᑱ</value>
+<value>ᑲ</value>
+<value>ᑳ</value>
+<value>ᑴ</value>
+<value>ᑵ</value>
+<value>ᑶ</value>
+<value>ᑷ</value>
+<value>ᑸ</value>
+<value>ᑹ</value>
+<value>ᒀ</value>
+<value>ᒁ</value>
+<value>ᒂ</value>
+<value>ᒃ</value>
+<value>ᒄ</value>
+<value>ᒅ</value>
+<value>ᒆ</value>
+<value>ᒇ</value>
+<value>ᒈ</value>
+<value>ᒉ</value>
+<value>ᒐ</value>
+<value>ᒑ</value>
+<value>ᒒ</value>
+<value>ᒓ</value>
+<value>ᒔ</value>
+<value>ᒕ</value>
+<value>ᒖ</value>
+<value>ᒗ</value>
+<value>ᒘ</value>
+<value>ᒙ</value>
+<value>ᔀ</value>
+<value>ᔁ</value>
+<value>ᔂ</value>
+<value>ᔃ</value>
+<value>ᔄ</value>
+<value>ᔅ</value>
+<value>ᔆ</value>
+<value>ᔇ</value>
+<value>ᔈ</value>
+<value>ᔉ</value>
+<value>ᔐ</value>
+<value>ᔑ</value>
+<value>ᔒ</value>
+<value>ᔓ</value>
+<value>ᔔ</value>
+<value>ᔕ</value>
+<value>ᔖ</value>
+<value>ᔗ</value>
+<value>ᔘ</value>
+<value>ᔙ</value>
+<value>ᔠ</value>
+<value>ᔡ</value>
+<value>ᔢ</value>
+<value>ᔣ</value>
+<value>ᔤ</value>
+<value>ᔥ</value>
+<value>ᔦ</value>
+<value>ᔧ</value>
+<value>ᔨ</value>
+<value>ᔩ</value>
+<value>ᔰ</value>
+<value>ᔱ</value>
+<value>ᔲ</value>
+<value>ᔳ</value>
+<value>ᔴ</value>
+<value>ᔵ</value>
+<value>ᔶ</value>
+<value>ᔷ</value>
+<value>ᔸ</value>
+<value>ᔹ</value>
+<value>ᕀ</value>
+<value>ᕁ</value>
+<value>ᕂ</value>
+<value>ᕃ</value>
+<value>ᕄ</value>
+<value>ᕅ</value>
+<value>ᕆ</value>
+<value>ᕇ</value>
+<value>ᕈ</value>
+<value>ᕉ</value>
+<value>ᕐ</value>
+<value>ᕑ</value>
+<value>ᕒ</value>
+<value>ᕓ</value>
+<value>ᕔ</value>
+<value>ᕕ</value>
+<value>ᕖ</value>
+<value>ᕗ</value>
+<value>ᕘ</value>
+<value>ᕙ</value>
+<value>ᕠ</value>
+<value>ᕡ</value>
+<value>ᕢ</value>
+<value>ᕣ</value>
+<value>ᕤ</value>
+<value>ᕥ</value>
+<value>ᕦ</value>
+<value>ᕧ</value>
+<value>ᕨ</value>
+<value>ᕩ</value>
+<value>ᕰ</value>
+<value>ᕱ</value>
+<value>ᕲ</value>
+<value>ᕳ</value>
+<value>ᕴ</value>
+<value>ᕵ</value>
+<value>ᕶ</value>
+<value>ᕷ</value>
+<value>ᕸ</value>
+<value>ᕹ</value>
+<value>ᖀ</value>
+<value>ᖁ</value>
+<value>ᖂ</value>
+<value>ᖃ</value>
+<value>ᖄ</value>
+<value>ᖅ</value>
+<value>ᖆ</value>
+<value>ᖇ</value>
+<value>ᖈ</value>
+<value>ᖉ</value>
+<value>ᖐ</value>
+<value>ᖑ</value>
+<value>ᖒ</value>
+<value>ᖓ</value>
+<value>ᖔ</value>
+<value>ᖕ</value>
+<value>ᖖ</value>
+<value>ᖗ</value>
+<value>ᖘ</value>
+<value>ᖙ</value>
+<value>ᘀ</value>
+<value>ᘁ</value>
+<value>ᘂ</value>
+<value>ᘃ</value>
+<value>ᘄ</value>
+<value>ᘅ</value>
+<value>ᘆ</value>
+<value>ᘇ</value>
+<value>ᘈ</value>
+<value>ᘉ</value>
+<value>ᘐ</value>
+<value>ᘑ</value>
+<value>ᘒ</value>
+<value>ᘓ</value>
+<value>ᘔ</value>
+<value>ᘕ</value>
+<value>ᘖ</value>
+<value>ᘗ</value>
+<value>ᘘ</value>
+<value>ᘙ</value>
+<value>ᘠ</value>
+<value>ᘡ</value>
+<value>ᘢ</value>
+<value>ᘣ</value>
+<value>ᘤ</value>
+<value>ᘥ</value>
+<value>ᘦ</value>
+<value>ᘧ</value>
+<value>ᘨ</value>
+<value>ᘩ</value>
+<value>ᘰ</value>
+<value>ᘱ</value>
+<value>ᘲ</value>
+<value>ᘳ</value>
+<value>ᘴ</value>
+<value>ᘵ</value>
+<value>ᘶ</value>
+<value>ᘷ</value>
+<value>ᘸ</value>
+<value>ᘹ</value>
+<value>ᙀ</value>
+<value>ᙁ</value>
+<value>ᙂ</value>
+<value>ᙃ</value>
+<value>ᙄ</value>
+<value>ᙅ</value>
+<value>ᙆ</value>
+<value>ᙇ</value>
+<value>ᙈ</value>
+<value>ᙉ</value>
+<value>ᙐ</value>
+<value>ᙑ</value>
+<value>ᙒ</value>
+<value>ᙓ</value>
+<value>ᙔ</value>
+<value>ᙕ</value>
+<value>ᙖ</value>
+<value>ᙗ</value>
+<value>ᙘ</value>
+<value>ᙙ</value>
+<value>ᙠ</value>
+<value>ᙡ</value>
+<value>ᙢ</value>
+<value>ᙣ</value>
+<value>ᙤ</value>
+<value>ᙥ</value>
+<value>ᙦ</value>
+<value>ᙧ</value>
+<value>ᙨ</value>
+<value>ᙩ</value>
+<value>ᙰ</value>
+<value>ᙱ</value>
+<value>ᙲ</value>
+<value>ᙳ</value>
+<value>ᙴ</value>
+<value>ᙵ</value>
+<value>ᙶ</value>
+<value>ᚁ</value>
+<value>ᚂ</value>
+<value>ᚃ</value>
+<value>ᚄ</value>
+<value>ᚅ</value>
+<value>ᚆ</value>
+<value>ᚇ</value>
+<value>ᚈ</value>
+<value>ᚉ</value>
+<value>ᚐ</value>
+<value>ᚑ</value>
+<value>ᚒ</value>
+<value>ᚓ</value>
+<value>ᚔ</value>
+<value>ᚕ</value>
+<value>ᚖ</value>
+<value>ᚗ</value>
+<value>ᚘ</value>
+<value>ᚙ</value>
+<value>ᜀ</value>
+<value>ᜁ</value>
+<value>ᜂ</value>
+<value>ᜃ</value>
+<value>ᜄ</value>
+<value>ᜅ</value>
+<value>ᜆ</value>
+<value>ᜇ</value>
+<value>ᜈ</value>
+<value>ᜉ</value>
+<value>ᜐ</value>
+<value>ᜑ</value>
+<value>ᜒ</value>
+<value>ᜓ</value>
+<value>᜔</value>
+<value>ᜠ</value>
+<value>ᜡ</value>
+<value>ᜢ</value>
+<value>ᜣ</value>
+<value>ᜤ</value>
+<value>ᜥ</value>
+<value>ᜦ</value>
+<value>ᜧ</value>
+<value>ᜨ</value>
+<value>ᜩ</value>
+<value>ᜰ</value>
+<value>ᜱ</value>
+<value>ᜲ</value>
+<value>ᜳ</value>
+<value>᜴</value>
+<value>ᝀ</value>
+<value>ᝁ</value>
+<value>ᝂ</value>
+<value>ᝃ</value>
+<value>ᝄ</value>
+<value>ᝅ</value>
+<value>ᝆ</value>
+<value>ᝇ</value>
+<value>ᝈ</value>
+<value>ᝉ</value>
+<value>ᝐ</value>
+<value>ᝑ</value>
+<value>ᝒ</value>
+<value>ᝓ</value>
+<value>ᝠ</value>
+<value>ᝡ</value>
+<value>ᝢ</value>
+<value>ᝣ</value>
+<value>ᝤ</value>
+<value>ᝥ</value>
+<value>ᝦ</value>
+<value>ᝧ</value>
+<value>ᝨ</value>
+<value>ᝩ</value>
+<value>ᝰ</value>
+<value>ᝲ</value>
+<value>ᝳ</value>
+<value>ក</value>
+<value>ខ</value>
+<value>គ</value>
+<value>ឃ</value>
+<value>ង</value>
+<value>ច</value>
+<value>ឆ</value>
+<value>ជ</value>
+<value>ឈ</value>
+<value>ញ</value>
+<value>ថ</value>
+<value>ទ</value>
+<value>ធ</value>
+<value>ន</value>
+<value>ប</value>
+<value>ផ</value>
+<value>ព</value>
+<value>ភ</value>
+<value>ម</value>
+<value>យ</value>
+<value>᠐</value>
+<value>᠑</value>
+<value>᠒</value>
+<value>᠓</value>
+<value>᠔</value>
+<value>᠕</value>
+<value>᠖</value>
+<value>᠗</value>
+<value>᠘</value>
+<value>᠙</value>
+<value>ᠠ</value>
+<value>ᠡ</value>
+<value>ᠢ</value>
+<value>ᠣ</value>
+<value>ᠤ</value>
+<value>ᠥ</value>
+<value>ᠦ</value>
+<value>ᠧ</value>
+<value>ᠨ</value>
+<value>ᠩ</value>
+<value>ᠰ</value>
+<value>ᠱ</value>
+<value>ᠲ</value>
+<value>ᠳ</value>
+<value>ᠴ</value>
+<value>ᠵ</value>
+<value>ᠶ</value>
+<value>ᠷ</value>
+<value>ᠸ</value>
+<value>ᠹ</value>
+<value>ᡀ</value>
+<value>ᡁ</value>
+<value>ᡂ</value>
+<value>ᡃ</value>
+<value>ᡄ</value>
+<value>ᡅ</value>
+<value>ᡆ</value>
+<value>ᡇ</value>
+<value>ᡈ</value>
+<value>ᡉ</value>
+<value>ᡐ</value>
+<value>ᡑ</value>
+<value>ᡒ</value>
+<value>ᡓ</value>
+<value>ᡔ</value>
+<value>ᡕ</value>
+<value>ᡖ</value>
+<value>ᡗ</value>
+<value>ᡘ</value>
+<value>ᡙ</value>
+<value>ᡠ</value>
+<value>ᡡ</value>
+<value>ᡢ</value>
+<value>ᡣ</value>
+<value>ᡤ</value>
+<value>ᡥ</value>
+<value>ᡦ</value>
+<value>ᡧ</value>
+<value>ᡨ</value>
+<value>ᡩ</value>
+<value>ᡰ</value>
+<value>ᡱ</value>
+<value>ᡲ</value>
+<value>ᡳ</value>
+<value>ᡴ</value>
+<value>ᡵ</value>
+<value>ᡶ</value>
+<value>ᡷ</value>
+<value>ᢀ</value>
+<value>ᢁ</value>
+<value>ᢂ</value>
+<value>ᢃ</value>
+<value>ᢄ</value>
+<value>ᢅ</value>
+<value>ᢆ</value>
+<value>ᢇ</value>
+<value>ᢈ</value>
+<value>ᢉ</value>
+<value>ᢐ</value>
+<value>ᢑ</value>
+<value>ᢒ</value>
+<value>ᢓ</value>
+<value>ᢔ</value>
+<value>ᢕ</value>
+<value>ᢖ</value>
+<value>ᢗ</value>
+<value>ᢘ</value>
+<value>ᢙ</value>
+<value>⁄</value>
+<value>⁒</value>
+<value>⁰</value>
+<value>ⁱ</value>
+<value>⁴</value>
+<value>⁵</value>
+<value>⁶</value>
+<value>⁷</value>
+<value>⁸</value>
+<value>⁹</value>
+<value>₀</value>
+<value>₁</value>
+<value>₂</value>
+<value>₃</value>
+<value>₄</value>
+<value>₅</value>
+<value>₆</value>
+<value>₇</value>
+<value>₈</value>
+<value>₉</value>
+<value>℀</value>
+<value>℁</value>
+<value>ℂ</value>
+<value>℃</value>
+<value>℄</value>
+<value>℅</value>
+<value>℆</value>
+<value>ℇ</value>
+<value>℈</value>
+<value>℉</value>
+<value>ℐ</value>
+<value>ℑ</value>
+<value>ℒ</value>
+<value>ℓ</value>
+<value>℔</value>
+<value>ℕ</value>
+<value>№</value>
+<value>℗</value>
+<value>℘</value>
+<value>ℙ</value>
+<value>℠</value>
+<value>℡</value>
+<value>™</value>
+<value>℣</value>
+<value>ℤ</value>
+<value>℥</value>
+<value>Ω</value>
+<value>℧</value>
+<value>ℨ</value>
+<value>℩</value>
+<value>ℰ</value>
+<value>ℱ</value>
+<value>Ⅎ</value>
+<value>ℳ</value>
+<value>ℴ</value>
+<value>ℵ</value>
+<value>ℶ</value>
+<value>ℷ</value>
+<value>ℸ</value>
+<value>ℹ</value>
+<value>⅀</value>
+<value>⅁</value>
+<value>⅂</value>
+<value>⅃</value>
+<value>⅄</value>
+<value>ⅅ</value>
+<value>ⅆ</value>
+<value>ⅇ</value>
+<value>ⅈ</value>
+<value>ⅉ</value>
+<value>⅓</value>
+<value>⅔</value>
+<value>⅕</value>
+<value>⅖</value>
+<value>⅗</value>
+<value>⅘</value>
+<value>⅙</value>
+<value>Ⅰ</value>
+<value>Ⅱ</value>
+<value>Ⅲ</value>
+<value>Ⅳ</value>
+<value>Ⅴ</value>
+<value>Ⅵ</value>
+<value>Ⅶ</value>
+<value>Ⅷ</value>
+<value>Ⅸ</value>
+<value>Ⅹ</value>
+<value>ⅰ</value>
+<value>ⅱ</value>
+<value>ⅲ</value>
+<value>ⅳ</value>
+<value>ⅴ</value>
+<value>ⅵ</value>
+<value>ⅶ</value>
+<value>ⅷ</value>
+<value>ⅸ</value>
+<value>ⅹ</value>
+<value>ↀ</value>
+<value>ↁ</value>
+<value>ↂ</value>
+<value>Ↄ</value>
+<value>←</value>
+<value>↑</value>
+<value>→</value>
+<value>↓</value>
+<value>↔</value>
+<value>↕</value>
+<value>↖</value>
+<value>↗</value>
+<value>↘</value>
+<value>↙</value>
+<value>∀</value>
+<value>∁</value>
+<value>∂</value>
+<value>∃</value>
+<value>∄</value>
+<value>∅</value>
+<value>∆</value>
+<value>∇</value>
+<value>∈</value>
+<value>∉</value>
+<value>∐</value>
+<value>∑</value>
+<value>−</value>
+<value>∓</value>
+<value>∔</value>
+<value>∕</value>
+<value>∖</value>
+<value>∗</value>
+<value>∘</value>
+<value>∙</value>
+<value>∠</value>
+<value>∡</value>
+<value>∢</value>
+<value>∣</value>
+<value>∤</value>
+<value>∥</value>
+<value>∦</value>
+<value>∧</value>
+<value>∨</value>
+<value>∩</value>
+<value>∰</value>
+<value>∱</value>
+<value>∲</value>
+<value>∳</value>
+<value>∴</value>
+<value>∵</value>
+<value>∶</value>
+<value>∷</value>
+<value>∸</value>
+<value>∹</value>
+<value>≀</value>
+<value>≁</value>
+<value>≂</value>
+<value>≃</value>
+<value>≄</value>
+<value>≅</value>
+<value>≆</value>
+<value>≇</value>
+<value>≈</value>
+<value>≉</value>
+<value>≐</value>
+<value>≑</value>
+<value>≒</value>
+<value>≓</value>
+<value>≔</value>
+<value>≕</value>
+<value>≖</value>
+<value>≗</value>
+<value>≘</value>
+<value>≙</value>
+<value>≠</value>
+<value>≡</value>
+<value>≢</value>
+<value>≣</value>
+<value>≤</value>
+<value>≥</value>
+<value>≦</value>
+<value>≧</value>
+<value>≨</value>
+<value>≩</value>
+<value>≰</value>
+<value>≱</value>
+<value>≲</value>
+<value>≳</value>
+<value>≴</value>
+<value>≵</value>
+<value>≶</value>
+<value>≷</value>
+<value>≸</value>
+<value>≹</value>
+<value>⊀</value>
+<value>⊁</value>
+<value>⊂</value>
+<value>⊃</value>
+<value>⊄</value>
+<value>⊅</value>
+<value>⊆</value>
+<value>⊇</value>
+<value>⊈</value>
+<value>⊉</value>
+<value>⊐</value>
+<value>⊑</value>
+<value>⊒</value>
+<value>⊓</value>
+<value>⊔</value>
+<value>⊕</value>
+<value>⊖</value>
+<value>⊗</value>
+<value>⊘</value>
+<value>⊙</value>
+<value>⌀</value>
+<value>⌁</value>
+<value>⌂</value>
+<value>⌃</value>
+<value>⌄</value>
+<value>⌅</value>
+<value>⌆</value>
+<value>⌇</value>
+<value>⌐</value>
+<value>⌑</value>
+<value>⌒</value>
+<value>⌓</value>
+<value>⌔</value>
+<value>⌕</value>
+<value>⌖</value>
+<value>⌗</value>
+<value>⌘</value>
+<value>⌙</value>
+<value>⌠</value>
+<value>⌡</value>
+<value>⌢</value>
+<value>⌣</value>
+<value>⌤</value>
+<value>⌥</value>
+<value>⌦</value>
+<value>⌧</value>
+<value>⌨</value>
+<value>⌰</value>
+<value>⌱</value>
+<value>⌲</value>
+<value>⌳</value>
+<value>⌴</value>
+<value>⌵</value>
+<value>⌶</value>
+<value>⌷</value>
+<value>⌸</value>
+<value>⌹</value>
+<value>⍀</value>
+<value>⍁</value>
+<value>⍂</value>
+<value>⍃</value>
+<value>⍄</value>
+<value>⍅</value>
+<value>⍆</value>
+<value>⍇</value>
+<value>⍈</value>
+<value>⍉</value>
+<value>⍐</value>
+<value>⍑</value>
+<value>⍒</value>
+<value>⍓</value>
+<value>⍔</value>
+<value>⍕</value>
+<value>⍖</value>
+<value>⍗</value>
+<value>⍘</value>
+<value>⍙</value>
+<value>⍠</value>
+<value>⍡</value>
+<value>⍢</value>
+<value>⍣</value>
+<value>⍤</value>
+<value>⍥</value>
+<value>⍦</value>
+<value>⍧</value>
+<value>⍨</value>
+<value>⍩</value>
+<value>⍰</value>
+<value>⍱</value>
+<value>⍲</value>
+<value>⍳</value>
+<value>⍴</value>
+<value>⍵</value>
+<value>⍶</value>
+<value>⍷</value>
+<value>⍸</value>
+<value>⍹</value>
+<value>⎀</value>
+<value>⎁</value>
+<value>⎂</value>
+<value>⎃</value>
+<value>⎄</value>
+<value>⎅</value>
+<value>⎆</value>
+<value>⎇</value>
+<value>⎈</value>
+<value>⎉</value>
+<value>⎐</value>
+<value>⎑</value>
+<value>⎒</value>
+<value>⎓</value>
+<value>⎔</value>
+<value>⎕</value>
+<value>⎖</value>
+<value>⎗</value>
+<value>⎘</value>
+<value>⎙</value>
+<value>␀</value>
+<value>␁</value>
+<value>␂</value>
+<value>␃</value>
+<value>␄</value>
+<value>␅</value>
+<value>␆</value>
+<value>␇</value>
+<value>␈</value>
+<value>␉</value>
+<value>␐</value>
+<value>␑</value>
+<value>␒</value>
+<value>␓</value>
+<value>␔</value>
+<value>␕</value>
+<value>␖</value>
+<value>␗</value>
+<value>␘</value>
+<value>␙</value>
+<value>␠</value>
+<value>␡</value>
+<value>␢</value>
+<value>␣</value>
+<value>␤</value>
+<value>␥</value>
+<value>␦</value>
+<value>⑀</value>
+<value>⑁</value>
+<value>⑂</value>
+<value>⑃</value>
+<value>⑄</value>
+<value>⑅</value>
+<value>⑆</value>
+<value>⑇</value>
+<value>⑈</value>
+<value>⑉</value>
+<value>①</value>
+<value>②</value>
+<value>③</value>
+<value>④</value>
+<value>⑤</value>
+<value>⑥</value>
+<value>⑦</value>
+<value>⑧</value>
+<value>⑨</value>
+<value>⑩</value>
+<value>⑰</value>
+<value>⑱</value>
+<value>⑲</value>
+<value>⑳</value>
+<value>⑴</value>
+<value>⑵</value>
+<value>⑶</value>
+<value>⑷</value>
+<value>⑸</value>
+<value>⑹</value>
+<value>⒀</value>
+<value>⒁</value>
+<value>⒂</value>
+<value>⒃</value>
+<value>⒄</value>
+<value>⒅</value>
+<value>⒆</value>
+<value>⒇</value>
+<value>⒈</value>
+<value>⒉</value>
+<value>⒐</value>
+<value>⒑</value>
+<value>⒒</value>
+<value>⒓</value>
+<value>⒔</value>
+<value>⒕</value>
+<value>⒖</value>
+<value>⒗</value>
+<value>⒘</value>
+<value>⒙</value>
+<value>─</value>
+<value>━</value>
+<value>│</value>
+<value>┃</value>
+<value>┄</value>
+<value>┅</value>
+<value>┆</value>
+<value>┇</value>
+<value>┈</value>
+<value>┉</value>
+<value>┐</value>
+<value>┑</value>
+<value>┒</value>
+<value>┓</value>
+<value>└</value>
+<value>┕</value>
+<value>┖</value>
+<value>┗</value>
+<value>┘</value>
+<value>┙</value>
+<value>┠</value>
+<value>┡</value>
+<value>┢</value>
+<value>┣</value>
+<value>┤</value>
+<value>┥</value>
+<value>┦</value>
+<value>┧</value>
+<value>┨</value>
+<value>┩</value>
+<value>┰</value>
+<value>┱</value>
+<value>┲</value>
+<value>┳</value>
+<value>┴</value>
+<value>┵</value>
+<value>┶</value>
+<value>┷</value>
+<value>┸</value>
+<value>┹</value>
+<value>╀</value>
+<value>╁</value>
+<value>╂</value>
+<value>╃</value>
+<value>╄</value>
+<value>╅</value>
+<value>╆</value>
+<value>╇</value>
+<value>╈</value>
+<value>╉</value>
+<value>═</value>
+<value>║</value>
+<value>╒</value>
+<value>╓</value>
+<value>╔</value>
+<value>╕</value>
+<value>╖</value>
+<value>╗</value>
+<value>╘</value>
+<value>╙</value>
+<value>╠</value>
+<value>╡</value>
+<value>╢</value>
+<value>╣</value>
+<value>╤</value>
+<value>╥</value>
+<value>╦</value>
+<value>╧</value>
+<value>╨</value>
+<value>╩</value>
+<value>╰</value>
+<value>╱</value>
+<value>╲</value>
+<value>╳</value>
+<value>╴</value>
+<value>╵</value>
+<value>╶</value>
+<value>╷</value>
+<value>╸</value>
+<value>╹</value>
+<value>▀</value>
+<value>▁</value>
+<value>▂</value>
+<value>▃</value>
+<value>▄</value>
+<value>▅</value>
+<value>▆</value>
+<value>▇</value>
+<value>█</value>
+<value>▉</value>
+<value>▐</value>
+<value>░</value>
+<value>▒</value>
+<value>▓</value>
+<value>▔</value>
+<value>▕</value>
+<value>▖</value>
+<value>▗</value>
+<value>▘</value>
+<value>▙</value>
+<value>☀</value>
+<value>☁</value>
+<value>☂</value>
+<value>☃</value>
+<value>☄</value>
+<value>★</value>
+<value>☆</value>
+<value>☇</value>
+<value>☈</value>
+<value>☉</value>
+<value>☐</value>
+<value>☑</value>
+<value>☒</value>
+<value>☓</value>
+<value>☖</value>
+<value>☗</value>
+<value>☙</value>
+<value>☠</value>
+<value>☡</value>
+<value>☢</value>
+<value>☣</value>
+<value>☤</value>
+<value>☥</value>
+<value>☦</value>
+<value>☧</value>
+<value>☨</value>
+<value>☩</value>
+<value>☰</value>
+<value>☱</value>
+<value>☲</value>
+<value>☳</value>
+<value>☴</value>
+<value>☵</value>
+<value>☶</value>
+<value>☷</value>
+<value>☸</value>
+<value>☹</value>
+<value>♀</value>
+<value>♁</value>
+<value>♂</value>
+<value>♃</value>
+<value>♄</value>
+<value>♅</value>
+<value>♆</value>
+<value>♇</value>
+<value>♈</value>
+<value>♉</value>
+<value>♐</value>
+<value>♑</value>
+<value>♒</value>
+<value>♓</value>
+<value>♔</value>
+<value>♕</value>
+<value>♖</value>
+<value>♗</value>
+<value>♘</value>
+<value>♙</value>
+<value>♠</value>
+<value>♡</value>
+<value>♢</value>
+<value>♣</value>
+<value>♤</value>
+<value>♥</value>
+<value>♦</value>
+<value>♧</value>
+<value>♨</value>
+<value>♩</value>
+<value>♰</value>
+<value>♱</value>
+<value>♲</value>
+<value>♳</value>
+<value>♴</value>
+<value>♵</value>
+<value>♶</value>
+<value>♷</value>
+<value>♸</value>
+<value>♹</value>
+<value>⚀</value>
+<value>⚁</value>
+<value>⚂</value>
+<value>⚃</value>
+<value>⚄</value>
+<value>⚅</value>
+<value>⚆</value>
+<value>⚇</value>
+<value>⚈</value>
+<value>⚉</value>
+<value>✁</value>
+<value>✂</value>
+<value>✃</value>
+<value>✄</value>
+<value>✆</value>
+<value>✇</value>
+<value>✈</value>
+<value>✉</value>
+<value>✐</value>
+<value>✑</value>
+<value>✒</value>
+<value>✓</value>
+<value>✔</value>
+<value>✕</value>
+<value>✖</value>
+<value>✗</value>
+<value>✘</value>
+<value>✙</value>
+<value>✠</value>
+<value>✡</value>
+<value>✢</value>
+<value>✣</value>
+<value>✤</value>
+<value>✥</value>
+<value>✦</value>
+<value>✧</value>
+<value>✩</value>
+<value>✰</value>
+<value>✱</value>
+<value>✲</value>
+<value>✳</value>
+<value>✴</value>
+<value>✵</value>
+<value>✶</value>
+<value>✷</value>
+<value>✸</value>
+<value>✹</value>
+<value>❀</value>
+<value>❁</value>
+<value>❂</value>
+<value>❃</value>
+<value>❄</value>
+<value>❅</value>
+<value>❆</value>
+<value>❇</value>
+<value>❈</value>
+<value>❉</value>
+<value>❐</value>
+<value>❑</value>
+<value>❒</value>
+<value>❖</value>
+<value>❘</value>
+<value>❙</value>
+<value>❡</value>
+<value>❢</value>
+<value>❣</value>
+<value>❤</value>
+<value>❥</value>
+<value>❦</value>
+<value>❧</value>
+<value>❶</value>
+<value>❷</value>
+<value>❸</value>
+<value>❹</value>
+<value>➀</value>
+<value>➁</value>
+<value>➂</value>
+<value>➃</value>
+<value>➄</value>
+<value>➅</value>
+<value>➆</value>
+<value>➇</value>
+<value>➈</value>
+<value>➉</value>
+<value>➐</value>
+<value>➑</value>
+<value>➒</value>
+<value>➓</value>
+<value>➔</value>
+<value>➘</value>
+<value>➙</value>
+<value>⠀</value>
+<value>⠁</value>
+<value>⠂</value>
+<value>⠃</value>
+<value>⠄</value>
+<value>⠅</value>
+<value>⠆</value>
+<value>⠇</value>
+<value>⠈</value>
+<value>⠉</value>
+<value>⠐</value>
+<value>⠑</value>
+<value>⠒</value>
+<value>⠓</value>
+<value>⠔</value>
+<value>⠕</value>
+<value>⠖</value>
+<value>⠗</value>
+<value>⠘</value>
+<value>⠙</value>
+<value>⠠</value>
+<value>⠡</value>
+<value>⠢</value>
+<value>⠣</value>
+<value>⠤</value>
+<value>⠥</value>
+<value>⠦</value>
+<value>⠧</value>
+<value>⠨</value>
+<value>⠩</value>
+<value>⠰</value>
+<value>⠱</value>
+<value>⠲</value>
+<value>⠳</value>
+<value>⠴</value>
+<value>⠵</value>
+<value>⠶</value>
+<value>⠷</value>
+<value>⠸</value>
+<value>⠹</value>
+<value>⡀</value>
+<value>⡁</value>
+<value>⡂</value>
+<value>⡃</value>
+<value>⡄</value>
+<value>⡅</value>
+<value>⡆</value>
+<value>⡇</value>
+<value>⡈</value>
+<value>⡉</value>
+<value>⡐</value>
+<value>⡑</value>
+<value>⡒</value>
+<value>⡓</value>
+<value>⡔</value>
+<value>⡕</value>
+<value>⡖</value>
+<value>⡗</value>
+<value>⡘</value>
+<value>⡙</value>
+<value>⡠</value>
+<value>⡡</value>
+<value>⡢</value>
+<value>⡣</value>
+<value>⡤</value>
+<value>⡥</value>
+<value>⡦</value>
+<value>⡧</value>
+<value>⡨</value>
+<value>⡩</value>
+<value>⡰</value>
+<value>⡱</value>
+<value>⡲</value>
+<value>⡳</value>
+<value>⡴</value>
+<value>⡵</value>
+<value>⡶</value>
+<value>⡷</value>
+<value>⡸</value>
+<value>⡹</value>
+<value>⢀</value>
+<value>⢁</value>
+<value>⢂</value>
+<value>⢃</value>
+<value>⢄</value>
+<value>⢅</value>
+<value>⢆</value>
+<value>⢇</value>
+<value>⢈</value>
+<value>⢉</value>
+<value>⢐</value>
+<value>⢑</value>
+<value>⢒</value>
+<value>⢓</value>
+<value>⢔</value>
+<value>⢕</value>
+<value>⢖</value>
+<value>⢗</value>
+<value>⢘</value>
+<value>⢙</value>
+<value>⤀</value>
+<value>⤁</value>
+<value>⤂</value>
+<value>⤃</value>
+<value>⤄</value>
+<value>⤅</value>
+<value>⤆</value>
+<value>⤇</value>
+<value>⤈</value>
+<value>⤉</value>
+<value>⤐</value>
+<value>⤑</value>
+<value>⤒</value>
+<value>⤓</value>
+<value>⤔</value>
+<value>⤕</value>
+<value>⤖</value>
+<value>⤗</value>
+<value>⤘</value>
+<value>⤙</value>
+<value>⤠</value>
+<value>⤡</value>
+<value>⤢</value>
+<value>⤣</value>
+<value>⤤</value>
+<value>⤥</value>
+<value>⤦</value>
+<value>⤧</value>
+<value>⤨</value>
+<value>⤩</value>
+<value>⤰</value>
+<value>⤱</value>
+<value>⤲</value>
+<value>⤳</value>
+<value>⤴</value>
+<value>⤵</value>
+<value>⤶</value>
+<value>⤷</value>
+<value>⤸</value>
+<value>⤹</value>
+<value>⥀</value>
+<value>⥁</value>
+<value>⥂</value>
+<value>⥃</value>
+<value>⥄</value>
+<value>⥅</value>
+<value>⥆</value>
+<value>⥇</value>
+<value>⥈</value>
+<value>⥉</value>
+<value>⥐</value>
+<value>⥑</value>
+<value>⥒</value>
+<value>⥓</value>
+<value>⥔</value>
+<value>⥕</value>
+<value>⥖</value>
+<value>⥗</value>
+<value>⥘</value>
+<value>⥙</value>
+<value>⥠</value>
+<value>⥡</value>
+<value>⥢</value>
+<value>⥣</value>
+<value>⥤</value>
+<value>⥥</value>
+<value>⥦</value>
+<value>⥧</value>
+<value>⥨</value>
+<value>⥩</value>
+<value>⥰</value>
+<value>⥱</value>
+<value>⥲</value>
+<value>⥳</value>
+<value>⥴</value>
+<value>⥵</value>
+<value>⥶</value>
+<value>⥷</value>
+<value>⥸</value>
+<value>⥹</value>
+<value>⦀</value>
+<value>⦁</value>
+<value>⦂</value>
+<value>⦙</value>
+<value>〄</value>
+<value>々</value>
+<value>〆</value>
+<value>〇</value>
+<value>〒</value>
+<value>〓</value>
+<value>〠</value>
+<value>〡</value>
+<value>〢</value>
+<value>〣</value>
+<value>〤</value>
+<value>〥</value>
+<value>〦</value>
+<value>〧</value>
+<value>〨</value>
+<value>〩</value>
+<value>〱</value>
+<value>〲</value>
+<value>〳</value>
+<value>〴</value>
+<value>〵</value>
+<value>〶</value>
+<value>〷</value>
+<value>〸</value>
+<value>〹</value>
+<value>ぁ</value>
+<value>あ</value>
+<value>ぃ</value>
+<value>い</value>
+<value>ぅ</value>
+<value>う</value>
+<value>ぇ</value>
+<value>え</value>
+<value>ぉ</value>
+<value>ぐ</value>
+<value>け</value>
+<value>げ</value>
+<value>こ</value>
+<value>ご</value>
+<value>さ</value>
+<value>ざ</value>
+<value>し</value>
+<value>じ</value>
+<value>す</value>
+<value>だ</value>
+<value>ち</value>
+<value>ぢ</value>
+<value>っ</value>
+<value>つ</value>
+<value>づ</value>
+<value>て</value>
+<value>で</value>
+<value>と</value>
+<value>ど</value>
+<value>ば</value>
+<value>ぱ</value>
+<value>ひ</value>
+<value>び</value>
+<value>ぴ</value>
+<value>ふ</value>
+<value>ぶ</value>
+<value>ぷ</value>
+<value>へ</value>
+<value>べ</value>
+<value>む</value>
+<value>め</value>
+<value>も</value>
+<value>ゃ</value>
+<value>や</value>
+<value>ゅ</value>
+<value>ゆ</value>
+<value>ょ</value>
+<value>よ</value>
+<value>ら</value>
+<value>ゐ</value>
+<value>ゑ</value>
+<value>を</value>
+<value>ん</value>
+<value>ゔ</value>
+<value>ゕ</value>
+<value>ゖ</value>
+<value>゙</value>
+<value>ㄅ</value>
+<value>ㄆ</value>
+<value>ㄇ</value>
+<value>ㄈ</value>
+<value>ㄉ</value>
+<value>ㄐ</value>
+<value>ㄑ</value>
+<value>ㄒ</value>
+<value>ㄓ</value>
+<value>ㄔ</value>
+<value>ㄕ</value>
+<value>ㄖ</value>
+<value>ㄗ</value>
+<value>ㄘ</value>
+<value>ㄙ</value>
+<value>ㄠ</value>
+<value>ㄡ</value>
+<value>ㄢ</value>
+<value>ㄣ</value>
+<value>ㄤ</value>
+<value>ㄥ</value>
+<value>ㄦ</value>
+<value>ㄧ</value>
+<value>ㄨ</value>
+<value>ㄩ</value>
+<value>ㄱ</value>
+<value>ㄲ</value>
+<value>ㄳ</value>
+<value>ㄴ</value>
+<value>ㄵ</value>
+<value>ㄶ</value>
+<value>ㄷ</value>
+<value>ㄸ</value>
+<value>ㄹ</value>
+<value>ㅀ</value>
+<value>ㅁ</value>
+<value>ㅂ</value>
+<value>ㅃ</value>
+<value>ㅄ</value>
+<value>ㅅ</value>
+<value>ㅆ</value>
+<value>ㅇ</value>
+<value>ㅈ</value>
+<value>ㅉ</value>
+<value>ㅐ</value>
+<value>ㅑ</value>
+<value>ㅒ</value>
+<value>ㅓ</value>
+<value>ㅔ</value>
+<value>ㅕ</value>
+<value>ㅖ</value>
+<value>ㅗ</value>
+<value>ㅘ</value>
+<value>ㅙ</value>
+<value>ㅠ</value>
+<value>ㅡ</value>
+<value>ㅢ</value>
+<value>ㅣ</value>
+<value>ㅤ</value>
+<value>ㅥ</value>
+<value>ㅦ</value>
+<value>ㅧ</value>
+<value>ㅨ</value>
+<value>ㅩ</value>
+<value>ㅰ</value>
+<value>ㅱ</value>
+<value>ㅲ</value>
+<value>ㅳ</value>
+<value>ㅴ</value>
+<value>ㅵ</value>
+<value>ㅶ</value>
+<value>ㅷ</value>
+<value>ㅸ</value>
+<value>ㅹ</value>
+<value>ㆀ</value>
+<value>ㆁ</value>
+<value>ㆂ</value>
+<value>ㆃ</value>
+<value>ㆄ</value>
+<value>ㆅ</value>
+<value>ㆆ</value>
+<value>ㆇ</value>
+<value>ㆈ</value>
+<value>ㆉ</value>
+<value>㆐</value>
+<value>㆑</value>
+<value>㆒</value>
+<value>㆓</value>
+<value>㆔</value>
+<value>㆕</value>
+<value>㆖</value>
+<value>㆗</value>
+<value>㆘</value>
+<value>㆙</value>
+<value>㈀</value>
+<value>㈁</value>
+<value>㈂</value>
+<value>㈃</value>
+<value>㈄</value>
+<value>㈅</value>
+<value>㈆</value>
+<value>㈇</value>
+<value>㈈</value>
+<value>㈉</value>
+<value>㈐</value>
+<value>㈑</value>
+<value>㈒</value>
+<value>㈓</value>
+<value>㈔</value>
+<value>㈕</value>
+<value>㈖</value>
+<value>㈗</value>
+<value>㈘</value>
+<value>㈙</value>
+<value>㈠</value>
+<value>㈡</value>
+<value>㈢</value>
+<value>㈣</value>
+<value>㈤</value>
+<value>㈥</value>
+<value>㈦</value>
+<value>㈧</value>
+<value>㈨</value>
+<value>㈩</value>
+<value>㈰</value>
+<value>㈱</value>
+<value>㈲</value>
+<value>㈳</value>
+<value>㈴</value>
+<value>㈵</value>
+<value>㈶</value>
+<value>㈷</value>
+<value>㈸</value>
+<value>㈹</value>
+<value>㉀</value>
+<value>㉁</value>
+<value>㉂</value>
+<value>㉃</value>
+<value>㉑</value>
+<value>㉒</value>
+<value>㉓</value>
+<value>㉔</value>
+<value>㉕</value>
+<value>㉖</value>
+<value>㉗</value>
+<value>㉘</value>
+<value>㉙</value>
+<value>㉠</value>
+<value>㉡</value>
+<value>㉢</value>
+<value>㉣</value>
+<value>㉤</value>
+<value>㉥</value>
+<value>㉦</value>
+<value>㉧</value>
+<value>㉨</value>
+<value>㉩</value>
+<value>㉰</value>
+<value>㉱</value>
+<value>㉲</value>
+<value>㉳</value>
+<value>㉴</value>
+<value>㉵</value>
+<value>㉶</value>
+<value>㉷</value>
+<value>㉸</value>
+<value>㉹</value>
+<value>㊀</value>
+<value>㊁</value>
+<value>㊂</value>
+<value>㊃</value>
+<value>㊄</value>
+<value>㊅</value>
+<value>㊆</value>
+<value>㊇</value>
+<value>㊈</value>
+<value>㊉</value>
+<value>㊐</value>
+<value>㊑</value>
+<value>㊒</value>
+<value>㊓</value>
+<value>㊔</value>
+<value>㊕</value>
+<value>㊖</value>
+<value>㊗</value>
+<value>㊘</value>
+<value>㊙</value>
+<value>㌀</value>
+<value>㌁</value>
+<value>㌂</value>
+<value>㌃</value>
+<value>㌄</value>
+<value>㌅</value>
+<value>㌆</value>
+<value>㌇</value>
+<value>㌈</value>
+<value>㌉</value>
+<value>㌐</value>
+<value>㌑</value>
+<value>㌒</value>
+<value>㌓</value>
+<value>㌔</value>
+<value>㌕</value>
+<value>㌖</value>
+<value>㌗</value>
+<value>㌘</value>
+<value>㌙</value>
+<value>㌠</value>
+<value>㌡</value>
+<value>㌢</value>
+<value>㌣</value>
+<value>㌤</value>
+<value>㌥</value>
+<value>㌦</value>
+<value>㌧</value>
+<value>㌨</value>
+<value>㌩</value>
+<value>㌰</value>
+<value>㌱</value>
+<value>㌲</value>
+<value>㌳</value>
+<value>㌴</value>
+<value>㌵</value>
+<value>㌶</value>
+<value>㌷</value>
+<value>㌸</value>
+<value>㌹</value>
+<value>㍀</value>
+<value>㍁</value>
+<value>㍂</value>
+<value>㍃</value>
+<value>㍄</value>
+<value>㍅</value>
+<value>㍆</value>
+<value>㍇</value>
+<value>㍈</value>
+<value>㍉</value>
+<value>㍐</value>
+<value>㍑</value>
+<value>㍒</value>
+<value>㍓</value>
+<value>㍔</value>
+<value>㍕</value>
+<value>㍖</value>
+<value>㍗</value>
+<value>㍘</value>
+<value>㍙</value>
+<value>㍠</value>
+<value>㍡</value>
+<value>㍢</value>
+<value>㍣</value>
+<value>㍤</value>
+<value>㍥</value>
+<value>㍦</value>
+<value>㍧</value>
+<value>㍨</value>
+<value>㍩</value>
+<value>㍰</value>
+<value>㍱</value>
+<value>㍲</value>
+<value>㍳</value>
+<value>㍴</value>
+<value>㍵</value>
+<value>㍶</value>
+<value>㎀</value>
+<value>㎁</value>
+<value>㎂</value>
+<value>㎃</value>
+<value>㎄</value>
+<value>㎅</value>
+<value>㎆</value>
+<value>㎇</value>
+<value>㎈</value>
+<value>㎉</value>
+<value>㎐</value>
+<value>㎑</value>
+<value>㎒</value>
+<value>㎓</value>
+<value>㎔</value>
+<value>㎕</value>
+<value>㎖</value>
+<value>㎗</value>
+<value>㎘</value>
+<value>㎙</value>
+<value>㐀</value>
+<value>㐁</value>
+<value>㐂</value>
+<value>㐃</value>
+<value>㐄</value>
+<value>㐅</value>
+<value>㐆</value>
+<value>㐇</value>
+<value>㐈</value>
+<value>㐉</value>
+<value>㐐</value>
+<value>㐑</value>
+<value>㐒</value>
+<value>㐓</value>
+<value>㐔</value>
+<value>㐕</value>
+<value>㐖</value>
+<value>㐗</value>
+<value>㐘</value>
+<value>㐙</value>
+<value>㐠</value>
+<value>㐡</value>
+<value>㐢</value>
+<value>㐣</value>
+<value>㐤</value>
+<value>㐥</value>
+<value>㐦</value>
+<value>㐧</value>
+<value>㐨</value>
+<value>㐩</value>
+<value>㐰</value>
+<value>㐱</value>
+<value>㐲</value>
+<value>㐳</value>
+<value>㐴</value>
+<value>㐵</value>
+<value>㐶</value>
+<value>㐷</value>
+<value>㐸</value>
+<value>㐹</value>
+<value>㑀</value>
+<value>㑁</value>
+<value>㑂</value>
+<value>㑃</value>
+<value>㑄</value>
+<value>㑅</value>
+<value>㑆</value>
+<value>㑇</value>
+<value>㑈</value>
+<value>㑉</value>
+<value>㑐</value>
+<value>㑑</value>
+<value>㑒</value>
+<value>㑓</value>
+<value>㑔</value>
+<value>㑕</value>
+<value>㑖</value>
+<value>㑗</value>
+<value>㑘</value>
+<value>㑙</value>
+<value>㑠</value>
+<value>㑡</value>
+<value>㑢</value>
+<value>㑣</value>
+<value>㑤</value>
+<value>㑥</value>
+<value>㑦</value>
+<value>㑧</value>
+<value>㑨</value>
+<value>㑩</value>
+<value>㑰</value>
+<value>㑱</value>
+<value>㑲</value>
+<value>㑳</value>
+<value>㑴</value>
+<value>㑵</value>
+<value>㑶</value>
+<value>㑷</value>
+<value>㑸</value>
+<value>㑹</value>
+<value>㒀</value>
+<value>㒁</value>
+<value>㒂</value>
+<value>㒃</value>
+<value>㒄</value>
+<value>㒅</value>
+<value>㒆</value>
+<value>㒇</value>
+<value>㒈</value>
+<value>㒉</value>
+<value>㒐</value>
+<value>㒑</value>
+<value>㒒</value>
+<value>㒓</value>
+<value>㒔</value>
+<value>㒕</value>
+<value>㒖</value>
+<value>㒗</value>
+<value>㒘</value>
+<value>㒙</value>
+<value>㔀</value>
+<value>㔁</value>
+<value>㔂</value>
+<value>㔃</value>
+<value>㔄</value>
+<value>㔅</value>
+<value>㔆</value>
+<value>㔇</value>
+<value>㔈</value>
+<value>㔉</value>
+<value>㔐</value>
+<value>㔑</value>
+<value>㔒</value>
+<value>㔓</value>
+<value>㔔</value>
+<value>㔕</value>
+<value>㔖</value>
+<value>㔗</value>
+<value>㔘</value>
+<value>㔙</value>
+<value>㔠</value>
+<value>㔡</value>
+<value>㔢</value>
+<value>㔣</value>
+<value>㔤</value>
+<value>㔥</value>
+<value>㔦</value>
+<value>㔧</value>
+<value>㔨</value>
+<value>㔩</value>
+<value>㔰</value>
+<value>㔱</value>
+<value>㔲</value>
+<value>㔳</value>
+<value>㔴</value>
+<value>㔵</value>
+<value>㔶</value>
+<value>㔷</value>
+<value>㔸</value>
+<value>㔹</value>
+<value>㕀</value>
+<value>㕁</value>
+<value>㕂</value>
+<value>㕃</value>
+<value>㕄</value>
+<value>㕅</value>
+<value>㕆</value>
+<value>㕇</value>
+<value>㕈</value>
+<value>㕉</value>
+<value>㕐</value>
+<value>㕑</value>
+<value>㕒</value>
+<value>㕓</value>
+<value>㕔</value>
+<value>㕕</value>
+<value>㕖</value>
+<value>㕗</value>
+<value>㕘</value>
+<value>㕙</value>
+<value>㕠</value>
+<value>㕡</value>
+<value>㕢</value>
+<value>㕣</value>
+<value>㕤</value>
+<value>㕥</value>
+<value>㕦</value>
+<value>㕧</value>
+<value>㕨</value>
+<value>㕩</value>
+<value>㕰</value>
+<value>㕱</value>
+<value>㕲</value>
+<value>㕳</value>
+<value>㕴</value>
+<value>㕵</value>
+<value>㕶</value>
+<value>㕷</value>
+<value>㕸</value>
+<value>㕹</value>
+<value>㖀</value>
+<value>㖁</value>
+<value>㖂</value>
+<value>㖃</value>
+<value>㖄</value>
+<value>㖅</value>
+<value>㖆</value>
+<value>㖇</value>
+<value>㖈</value>
+<value>㖉</value>
+<value>㖐</value>
+<value>㖑</value>
+<value>㖒</value>
+<value>㖓</value>
+<value>㖔</value>
+<value>㖕</value>
+<value>㖖</value>
+<value>㖗</value>
+<value>㖘</value>
+<value>㖙</value>
+<value>㘀</value>
+<value>㘁</value>
+<value>㘂</value>
+<value>㘃</value>
+<value>㘄</value>
+<value>㘅</value>
+<value>㘆</value>
+<value>㘇</value>
+<value>㘈</value>
+<value>㘉</value>
+<value>㘐</value>
+<value>㘑</value>
+<value>㘒</value>
+<value>㘓</value>
+<value>㘔</value>
+<value>㘕</value>
+<value>㘖</value>
+<value>㘗</value>
+<value>㘘</value>
+<value>㘙</value>
+<value>㘠</value>
+<value>㘡</value>
+<value>㘢</value>
+<value>㘣</value>
+<value>㘤</value>
+<value>㘥</value>
+<value>㘦</value>
+<value>㘧</value>
+<value>㘨</value>
+<value>㘩</value>
+<value>㘰</value>
+<value>㘱</value>
+<value>㘲</value>
+<value>㘳</value>
+<value>㘴</value>
+<value>㘵</value>
+<value>㘶</value>
+<value>㘷</value>
+<value>㘸</value>
+<value>㘹</value>
+<value>㙀</value>
+<value>㙁</value>
+<value>㙂</value>
+<value>㙃</value>
+<value>㙄</value>
+<value>㙅</value>
+<value>㙆</value>
+<value>㙇</value>
+<value>㙈</value>
+<value>㙉</value>
+<value>㙐</value>
+<value>㙑</value>
+<value>㙒</value>
+<value>㙓</value>
+<value>㙔</value>
+<value>㙕</value>
+<value>㙖</value>
+<value>㙗</value>
+<value>㙘</value>
+<value>㙙</value>
+<value>㙠</value>
+<value>㙡</value>
+<value>㙢</value>
+<value>㙣</value>
+<value>㙤</value>
+<value>㙥</value>
+<value>㙦</value>
+<value>㙧</value>
+<value>㙨</value>
+<value>㙩</value>
+<value>㙰</value>
+<value>㙱</value>
+<value>㙲</value>
+<value>㙳</value>
+<value>㙴</value>
+<value>㙵</value>
+<value>㙶</value>
+<value>㙷</value>
+<value>㙸</value>
+<value>㙹</value>
+<value>㚀</value>
+<value>㚁</value>
+<value>㚂</value>
+<value>㚃</value>
+<value>㚄</value>
+<value>㚅</value>
+<value>㚆</value>
+<value>㚇</value>
+<value>㚈</value>
+<value>㚉</value>
+<value>㚐</value>
+<value>㚑</value>
+<value>㚒</value>
+<value>㚓</value>
+<value>㚔</value>
+<value>㚕</value>
+<value>㚖</value>
+<value>㚗</value>
+<value>㚘</value>
+<value>㚙</value>
+<value>㜀</value>
+<value>㜁</value>
+<value>㜂</value>
+<value>㜃</value>
+<value>㜄</value>
+<value>㜅</value>
+<value>㜆</value>
+<value>㜇</value>
+<value>㜈</value>
+<value>㜉</value>
+<value>㜐</value>
+<value>㜑</value>
+<value>㜒</value>
+<value>㜓</value>
+<value>㜔</value>
+<value>㜕</value>
+<value>㜖</value>
+<value>㜗</value>
+<value>㜘</value>
+<value>㜙</value>
+<value>㜠</value>
+<value>㜡</value>
+<value>㜢</value>
+<value>㜣</value>
+<value>㜤</value>
+<value>㜥</value>
+<value>㜦</value>
+<value>㜧</value>
+<value>㜨</value>
+<value>㜩</value>
+<value>㜰</value>
+<value>㜱</value>
+<value>㜲</value>
+<value>㜳</value>
+<value>㜴</value>
+<value>㜵</value>
+<value>㜶</value>
+<value>㜷</value>
+<value>㜸</value>
+<value>㜹</value>
+<value>㝀</value>
+<value>㝁</value>
+<value>㝂</value>
+<value>㝃</value>
+<value>㝄</value>
+<value>㝅</value>
+<value>㝆</value>
+<value>㝇</value>
+<value>㝈</value>
+<value>㝉</value>
+<value>㝐</value>
+<value>㝑</value>
+<value>㝒</value>
+<value>㝓</value>
+<value>㝔</value>
+<value>㝕</value>
+<value>㝖</value>
+<value>㝗</value>
+<value>㝘</value>
+<value>㝙</value>
+<value>㝠</value>
+<value>㝡</value>
+<value>㝢</value>
+<value>㝣</value>
+<value>㝤</value>
+<value>㝥</value>
+<value>㝦</value>
+<value>㝧</value>
+<value>㝨</value>
+<value>㝩</value>
+<value>㝰</value>
+<value>㝱</value>
+<value>㝲</value>
+<value>㝳</value>
+<value>㝴</value>
+<value>㝵</value>
+<value>㝶</value>
+<value>㝷</value>
+<value>㝸</value>
+<value>㝹</value>
+<value>㞀</value>
+<value>㞁</value>
+<value>㞂</value>
+<value>㞃</value>
+<value>㞄</value>
+<value>㞅</value>
+<value>㞆</value>
+<value>㞇</value>
+<value>㞈</value>
+<value>㞉</value>
+<value>㞐</value>
+<value>㞑</value>
+<value>㞒</value>
+<value>㞓</value>
+<value>㞔</value>
+<value>㞕</value>
+<value>㞖</value>
+<value>㞗</value>
+<value>㞘</value>
+<value>㞙</value>
+<value>㠀</value>
+<value>㠁</value>
+<value>㠂</value>
+<value>㠃</value>
+<value>㠄</value>
+<value>㠅</value>
+<value>㠆</value>
+<value>㠇</value>
+<value>㠈</value>
+<value>㠉</value>
+<value>㠐</value>
+<value>㠑</value>
+<value>㠒</value>
+<value>㠓</value>
+<value>㠔</value>
+<value>㠕</value>
+<value>㠖</value>
+<value>㠗</value>
+<value>㠘</value>
+<value>㠙</value>
+<value>㠠</value>
+<value>㠡</value>
+<value>㠢</value>
+<value>㠣</value>
+<value>㠤</value>
+<value>㠥</value>
+<value>㠦</value>
+<value>㠧</value>
+<value>㠨</value>
+<value>㠩</value>
+<value>㠰</value>
+<value>㠱</value>
+<value>㠲</value>
+<value>㠳</value>
+<value>㠴</value>
+<value>㠵</value>
+<value>㠶</value>
+<value>㠷</value>
+<value>㠸</value>
+<value>㠹</value>
+<value>㡀</value>
+<value>㡁</value>
+<value>㡂</value>
+<value>㡃</value>
+<value>㡄</value>
+<value>㡅</value>
+<value>㡆</value>
+<value>㡇</value>
+<value>㡈</value>
+<value>㡉</value>
+<value>㡐</value>
+<value>㡑</value>
+<value>㡒</value>
+<value>㡓</value>
+<value>㡔</value>
+<value>㡕</value>
+<value>㡖</value>
+<value>㡗</value>
+<value>㡘</value>
+<value>㡙</value>
+<value>㡠</value>
+<value>㡡</value>
+<value>㡢</value>
+<value>㡣</value>
+<value>㡤</value>
+<value>㡥</value>
+<value>㡦</value>
+<value>㡧</value>
+<value>㡨</value>
+<value>㡩</value>
+<value>㡰</value>
+<value>㡱</value>
+<value>㡲</value>
+<value>㡳</value>
+<value>㡴</value>
+<value>㡵</value>
+<value>㡶</value>
+<value>㡷</value>
+<value>㡸</value>
+<value>㡹</value>
+<value>㢀</value>
+<value>㢁</value>
+<value>㢂</value>
+<value>㢃</value>
+<value>㢄</value>
+<value>㢅</value>
+<value>㢆</value>
+<value>㢇</value>
+<value>㢈</value>
+<value>㢉</value>
+<value>㢐</value>
+<value>㢑</value>
+<value>㢒</value>
+<value>㢓</value>
+<value>㢔</value>
+<value>㢕</value>
+<value>㢖</value>
+<value>㢗</value>
+<value>㢘</value>
+<value>㢙</value>
+<value>㤀</value>
+<value>㤁</value>
+<value>㤂</value>
+<value>㤃</value>
+<value>㤄</value>
+<value>㤅</value>
+<value>㤆</value>
+<value>㤇</value>
+<value>㤈</value>
+<value>㤉</value>
+<value>㤐</value>
+<value>㤑</value>
+<value>㤒</value>
+<value>㤓</value>
+<value>㤔</value>
+<value>㤕</value>
+<value>㤖</value>
+<value>㤗</value>
+<value>㤘</value>
+<value>㤙</value>
+<value>㤠</value>
+<value>㤡</value>
+<value>㤢</value>
+<value>㤣</value>
+<value>㤤</value>
+<value>㤥</value>
+<value>㤦</value>
+<value>㤧</value>
+<value>㤨</value>
+<value>㤩</value>
+<value>㤰</value>
+<value>㤱</value>
+<value>㤲</value>
+<value>㤳</value>
+<value>㤴</value>
+<value>㤵</value>
+<value>㤶</value>
+<value>㤷</value>
+<value>㤸</value>
+<value>㤹</value>
+<value>㥀</value>
+<value>㥁</value>
+<value>㥂</value>
+<value>㥃</value>
+<value>㥄</value>
+<value>㥅</value>
+<value>㥆</value>
+<value>㥇</value>
+<value>㥈</value>
+<value>㥉</value>
+<value>㥐</value>
+<value>㥑</value>
+<value>㥒</value>
+<value>㥓</value>
+<value>㥔</value>
+<value>㥕</value>
+<value>㥖</value>
+<value>㥗</value>
+<value>㥘</value>
+<value>㥙</value>
+<value>㥠</value>
+<value>㥡</value>
+<value>㥢</value>
+<value>㥣</value>
+<value>㥤</value>
+<value>㥥</value>
+<value>㥦</value>
+<value>㥧</value>
+<value>㥨</value>
+<value>㥩</value>
+<value>㥰</value>
+<value>㥱</value>
+<value>㥲</value>
+<value>㥳</value>
+<value>㥴</value>
+<value>㥵</value>
+<value>㥶</value>
+<value>㥷</value>
+<value>㥸</value>
+<value>㥹</value>
+<value>㦀</value>
+<value>㦁</value>
+<value>㦂</value>
+<value>㦃</value>
+<value>㦄</value>
+<value>㦅</value>
+<value>㦆</value>
+<value>㦇</value>
+<value>㦈</value>
+<value>㦉</value>
+<value>㦐</value>
+<value>㦑</value>
+<value>㦒</value>
+<value>㦓</value>
+<value>㦔</value>
+<value>㦕</value>
+<value>㦖</value>
+<value>㦗</value>
+<value>㦘</value>
+<value>㦙</value>
+<value>䀀</value>
+<value>䀁</value>
+<value>䀂</value>
+<value>䀃</value>
+<value>䀄</value>
+<value>䀅</value>
+<value>䀆</value>
+<value>䀇</value>
+<value>䀈</value>
+<value>䀉</value>
+<value>䀐</value>
+<value>䀑</value>
+<value>䀒</value>
+<value>䀓</value>
+<value>䀔</value>
+<value>䀕</value>
+<value>䀖</value>
+<value>䀗</value>
+<value>䀘</value>
+<value>䀙</value>
+<value>䀠</value>
+<value>䀡</value>
+<value>䀢</value>
+<value>䀣</value>
+<value>䀤</value>
+<value>䀥</value>
+<value>䀦</value>
+<value>䀧</value>
+<value>䀨</value>
+<value>䀩</value>
+<value>䀰</value>
+<value>䀱</value>
+<value>䀲</value>
+<value>䀳</value>
+<value>䀴</value>
+<value>䀵</value>
+<value>䀶</value>
+<value>䀷</value>
+<value>䀸</value>
+<value>䀹</value>
+<value>䁀</value>
+<value>䁁</value>
+<value>䁂</value>
+<value>䁃</value>
+<value>䁄</value>
+<value>䁅</value>
+<value>䁆</value>
+<value>䁇</value>
+<value>䁈</value>
+<value>䁉</value>
+<value>䁐</value>
+<value>䁑</value>
+<value>䁒</value>
+<value>䁓</value>
+<value>䁔</value>
+<value>䁕</value>
+<value>䁖</value>
+<value>䁗</value>
+<value>䁘</value>
+<value>䁙</value>
+<value>䁠</value>
+<value>䁡</value>
+<value>䁢</value>
+<value>䁣</value>
+<value>䁤</value>
+<value>䁥</value>
+<value>䁦</value>
+<value>䁧</value>
+<value>䁨</value>
+<value>䁩</value>
+<value>䁰</value>
+<value>䁱</value>
+<value>䁲</value>
+<value>䁳</value>
+<value>䁴</value>
+<value>䁵</value>
+<value>䁶</value>
+<value>䁷</value>
+<value>䁸</value>
+<value>䁹</value>
+<value>䂀</value>
+<value>䂁</value>
+<value>䂂</value>
+<value>䂃</value>
+<value>䂄</value>
+<value>䂅</value>
+<value>䂆</value>
+<value>䂇</value>
+<value>䂈</value>
+<value>䂉</value>
+<value>䂐</value>
+<value>䂑</value>
+<value>䂒</value>
+<value>䂓</value>
+<value>䂔</value>
+<value>䂕</value>
+<value>䂖</value>
+<value>䂗</value>
+<value>䂘</value>
+<value>䂙</value>
+<value>䄀</value>
+<value>䄁</value>
+<value>䄂</value>
+<value>䄃</value>
+<value>䄄</value>
+<value>䄅</value>
+<value>䄆</value>
+<value>䄇</value>
+<value>䄈</value>
+<value>䄉</value>
+<value>䄐</value>
+<value>䄑</value>
+<value>䄒</value>
+<value>䄓</value>
+<value>䄔</value>
+<value>䄕</value>
+<value>䄖</value>
+<value>䄗</value>
+<value>䄘</value>
+<value>䄙</value>
+<value>䄠</value>
+<value>䄡</value>
+<value>䄢</value>
+<value>䄣</value>
+<value>䄤</value>
+<value>䄥</value>
+<value>䄦</value>
+<value>䄧</value>
+<value>䄨</value>
+<value>䄩</value>
+<value>䄰</value>
+<value>䄱</value>
+<value>䄲</value>
+<value>䄳</value>
+<value>䄴</value>
+<value>䄵</value>
+<value>䄶</value>
+<value>䄷</value>
+<value>䄸</value>
+<value>䄹</value>
+<value>䅀</value>
+<value>䅁</value>
+<value>䅂</value>
+<value>䅃</value>
+<value>䅄</value>
+<value>䅅</value>
+<value>䅆</value>
+<value>䅇</value>
+<value>䅈</value>
+<value>䅉</value>
+<value>䅐</value>
+<value>䅑</value>
+<value>䅒</value>
+<value>䅓</value>
+<value>䅔</value>
+<value>䅕</value>
+<value>䅖</value>
+<value>䅗</value>
+<value>䅘</value>
+<value>䅙</value>
+<value>䅠</value>
+<value>䅡</value>
+<value>䅢</value>
+<value>䅣</value>
+<value>䅤</value>
+<value>䅥</value>
+<value>䅦</value>
+<value>䅧</value>
+<value>䅨</value>
+<value>䅩</value>
+<value>䅰</value>
+<value>䅱</value>
+<value>䅲</value>
+<value>䅳</value>
+<value>䅴</value>
+<value>䅵</value>
+<value>䅶</value>
+<value>䅷</value>
+<value>䅸</value>
+<value>䅹</value>
+<value>䆀</value>
+<value>䆁</value>
+<value>䆂</value>
+<value>䆃</value>
+<value>䆄</value>
+<value>䆅</value>
+<value>䆆</value>
+<value>䆇</value>
+<value>䆈</value>
+<value>䆉</value>
+<value>䆐</value>
+<value>䆑</value>
+<value>䆒</value>
+<value>䆓</value>
+<value>䆔</value>
+<value>䆕</value>
+<value>䆖</value>
+<value>䆗</value>
+<value>䆘</value>
+<value>䆙</value>
+<value>䈀</value>
+<value>䈁</value>
+<value>䈂</value>
+<value>䈃</value>
+<value>䈄</value>
+<value>䈅</value>
+<value>䈆</value>
+<value>䈇</value>
+<value>䈈</value>
+<value>䈉</value>
+<value>䈐</value>
+<value>䈑</value>
+<value>䈒</value>
+<value>䈓</value>
+<value>䈔</value>
+<value>䈕</value>
+<value>䈖</value>
+<value>䈗</value>
+<value>䈘</value>
+<value>䈙</value>
+<value>䈠</value>
+<value>䈡</value>
+<value>䈢</value>
+<value>䈣</value>
+<value>䈤</value>
+<value>䈥</value>
+<value>䈦</value>
+<value>䈧</value>
+<value>䈨</value>
+<value>䈩</value>
+<value>䈰</value>
+<value>䈱</value>
+<value>䈲</value>
+<value>䈳</value>
+<value>䈴</value>
+<value>䈵</value>
+<value>䈶</value>
+<value>䈷</value>
+<value>䈸</value>
+<value>䈹</value>
+<value>䉀</value>
+<value>䉁</value>
+<value>䉂</value>
+<value>䉃</value>
+<value>䉄</value>
+<value>䉅</value>
+<value>䉆</value>
+<value>䉇</value>
+<value>䉈</value>
+<value>䉉</value>
+<value>䉐</value>
+<value>䉑</value>
+<value>䉒</value>
+<value>䉓</value>
+<value>䉔</value>
+<value>䉕</value>
+<value>䉖</value>
+<value>䉗</value>
+<value>䉘</value>
+<value>䉙</value>
+<value>䉠</value>
+<value>䉡</value>
+<value>䉢</value>
+<value>䉣</value>
+<value>䉤</value>
+<value>䉥</value>
+<value>䉦</value>
+<value>䉧</value>
+<value>䉨</value>
+<value>䉩</value>
+<value>䉰</value>
+<value>䉱</value>
+<value>䉲</value>
+<value>䉳</value>
+<value>䉴</value>
+<value>䉵</value>
+<value>䉶</value>
+<value>䉷</value>
+<value>䉸</value>
+<value>䉹</value>
+<value>䊀</value>
+<value>䊁</value>
+<value>䊂</value>
+<value>䊃</value>
+<value>䊄</value>
+<value>䊅</value>
+<value>䊆</value>
+<value>䊇</value>
+<value>䊈</value>
+<value>䊉</value>
+<value>䊐</value>
+<value>䊑</value>
+<value>䊒</value>
+<value>䊓</value>
+<value>䊔</value>
+<value>䊕</value>
+<value>䊖</value>
+<value>䊗</value>
+<value>䊘</value>
+<value>䊙</value>
+<value>䌀</value>
+<value>䌁</value>
+<value>䌂</value>
+<value>䌃</value>
+<value>䌄</value>
+<value>䌅</value>
+<value>䌆</value>
+<value>䌇</value>
+<value>䌈</value>
+<value>䌉</value>
+<value>䌐</value>
+<value>䌑</value>
+<value>䌒</value>
+<value>䌓</value>
+<value>䌔</value>
+<value>䌕</value>
+<value>䌖</value>
+<value>䌗</value>
+<value>䌘</value>
+<value>䌙</value>
+<value>䌠</value>
+<value>䌡</value>
+<value>䌢</value>
+<value>䌣</value>
+<value>䌤</value>
+<value>䌥</value>
+<value>䌦</value>
+<value>䌧</value>
+<value>䌨</value>
+<value>䌩</value>
+<value>䌰</value>
+<value>䌱</value>
+<value>䌲</value>
+<value>䌳</value>
+<value>䌴</value>
+<value>䌵</value>
+<value>䌶</value>
+<value>䌷</value>
+<value>䌸</value>
+<value>䌹</value>
+<value>䍀</value>
+<value>䍁</value>
+<value>䍂</value>
+<value>䍃</value>
+<value>䍄</value>
+<value>䍅</value>
+<value>䍆</value>
+<value>䍇</value>
+<value>䍈</value>
+<value>䍉</value>
+<value>䍐</value>
+<value>䍑</value>
+<value>䍒</value>
+<value>䍓</value>
+<value>䍔</value>
+<value>䍕</value>
+<value>䍖</value>
+<value>䍗</value>
+<value>䍘</value>
+<value>䍙</value>
+<value>䍠</value>
+<value>䍡</value>
+<value>䍢</value>
+<value>䍣</value>
+<value>䍤</value>
+<value>䍥</value>
+<value>䍦</value>
+<value>䍧</value>
+<value>䍨</value>
+<value>䍩</value>
+<value>䍰</value>
+<value>䍱</value>
+<value>䍲</value>
+<value>䍳</value>
+<value>䍴</value>
+<value>䍵</value>
+<value>䍶</value>
+<value>䍷</value>
+<value>䍸</value>
+<value>䍹</value>
+<value>䎀</value>
+<value>䎁</value>
+<value>䎂</value>
+<value>䎃</value>
+<value>䎄</value>
+<value>䎅</value>
+<value>䎆</value>
+<value>䎇</value>
+<value>䎈</value>
+<value>䎉</value>
+<value>䎐</value>
+<value>䎑</value>
+<value>䎒</value>
+<value>䎓</value>
+<value>䎔</value>
+<value>䎕</value>
+<value>䎖</value>
+<value>䎗</value>
+<value>䎘</value>
+<value>䎙</value>
+<value>䐀</value>
+<value>䐁</value>
+<value>䐂</value>
+<value>䐃</value>
+<value>䐄</value>
+<value>䐅</value>
+<value>䐆</value>
+<value>䐇</value>
+<value>䐈</value>
+<value>䐉</value>
+<value>䐐</value>
+<value>䐑</value>
+<value>䐒</value>
+<value>䐓</value>
+<value>䐔</value>
+<value>䐕</value>
+<value>䐖</value>
+<value>䐗</value>
+<value>䐘</value>
+<value>䐙</value>
+<value>䐠</value>
+<value>䐡</value>
+<value>䐢</value>
+<value>䐣</value>
+<value>䐤</value>
+<value>䐥</value>
+<value>䐦</value>
+<value>䐧</value>
+<value>䐨</value>
+<value>䐩</value>
+<value>䐰</value>
+<value>䐱</value>
+<value>䐲</value>
+<value>䐳</value>
+<value>䐴</value>
+<value>䐵</value>
+<value>䐶</value>
+<value>䐷</value>
+<value>䐸</value>
+<value>䐹</value>
+<value>䑀</value>
+<value>䑁</value>
+<value>䑂</value>
+<value>䑃</value>
+<value>䑄</value>
+<value>䑅</value>
+<value>䑆</value>
+<value>䑇</value>
+<value>䑈</value>
+<value>䑉</value>
+<value>䑐</value>
+<value>䑑</value>
+<value>䑒</value>
+<value>䑓</value>
+<value>䑔</value>
+<value>䑕</value>
+<value>䑖</value>
+<value>䑗</value>
+<value>䑘</value>
+<value>䑙</value>
+<value>䑠</value>
+<value>䑡</value>
+<value>䑢</value>
+<value>䑣</value>
+<value>䑤</value>
+<value>䑥</value>
+<value>䑦</value>
+<value>䑧</value>
+<value>䑨</value>
+<value>䑩</value>
+<value>䑰</value>
+<value>䑱</value>
+<value>䑲</value>
+<value>䑳</value>
+<value>䑴</value>
+<value>䑵</value>
+<value>䑶</value>
+<value>䑷</value>
+<value>䑸</value>
+<value>䑹</value>
+<value>䒀</value>
+<value>䒁</value>
+<value>䒂</value>
+<value>䒃</value>
+<value>䒄</value>
+<value>䒅</value>
+<value>䒆</value>
+<value>䒇</value>
+<value>䒈</value>
+<value>䒉</value>
+<value>䒐</value>
+<value>䒑</value>
+<value>䒒</value>
+<value>䒓</value>
+<value>䒔</value>
+<value>䒕</value>
+<value>䒖</value>
+<value>䒗</value>
+<value>䒘</value>
+<value>䒙</value>
+<value>䔀</value>
+<value>䔁</value>
+<value>䔂</value>
+<value>䔃</value>
+<value>䔄</value>
+<value>䔅</value>
+<value>䔆</value>
+<value>䔇</value>
+<value>䔈</value>
+<value>䔉</value>
+<value>䔐</value>
+<value>䔑</value>
+<value>䔒</value>
+<value>䔓</value>
+<value>䔔</value>
+<value>䔕</value>
+<value>䔖</value>
+<value>䔗</value>
+<value>䔘</value>
+<value>䔙</value>
+<value>䔠</value>
+<value>䔡</value>
+<value>䔢</value>
+<value>䔣</value>
+<value>䔤</value>
+<value>䔥</value>
+<value>䔦</value>
+<value>䔧</value>
+<value>䔨</value>
+<value>䔩</value>
+<value>䔰</value>
+<value>䔱</value>
+<value>䔲</value>
+<value>䔳</value>
+<value>䔴</value>
+<value>䔵</value>
+<value>䔶</value>
+<value>䔷</value>
+<value>䔸</value>
+<value>䔹</value>
+<value>䕀</value>
+<value>䕁</value>
+<value>䕂</value>
+<value>䕃</value>
+<value>䕄</value>
+<value>䕅</value>
+<value>䕆</value>
+<value>䕇</value>
+<value>䕈</value>
+<value>䕉</value>
+<value>䕐</value>
+<value>䕑</value>
+<value>䕒</value>
+<value>䕓</value>
+<value>䕔</value>
+<value>䕕</value>
+<value>䕖</value>
+<value>䕗</value>
+<value>䕘</value>
+<value>䕙</value>
+<value>䕠</value>
+<value>䕡</value>
+<value>䕢</value>
+<value>䕣</value>
+<value>䕤</value>
+<value>䕥</value>
+<value>䕦</value>
+<value>䕧</value>
+<value>䕨</value>
+<value>䕩</value>
+<value>䕰</value>
+<value>䕱</value>
+<value>䕲</value>
+<value>䕳</value>
+<value>䕴</value>
+<value>䕵</value>
+<value>䕶</value>
+<value>䕷</value>
+<value>䕸</value>
+<value>䕹</value>
+<value>䖀</value>
+<value>䖁</value>
+<value>䖂</value>
+<value>䖃</value>
+<value>䖄</value>
+<value>䖅</value>
+<value>䖆</value>
+<value>䖇</value>
+<value>䖈</value>
+<value>䖉</value>
+<value>䖐</value>
+<value>䖑</value>
+<value>䖒</value>
+<value>䖓</value>
+<value>䖔</value>
+<value>䖕</value>
+<value>䖖</value>
+<value>䖗</value>
+<value>䖘</value>
+<value>䖙</value>
+<value>䘀</value>
+<value>䘁</value>
+<value>䘂</value>
+<value>䘃</value>
+<value>䘄</value>
+<value>䘅</value>
+<value>䘆</value>
+<value>䘇</value>
+<value>䘈</value>
+<value>䘉</value>
+<value>䘐</value>
+<value>䘑</value>
+<value>䘒</value>
+<value>䘓</value>
+<value>䘔</value>
+<value>䘕</value>
+<value>䘖</value>
+<value>䘗</value>
+<value>䘘</value>
+<value>䘙</value>
+<value>䘠</value>
+<value>䘡</value>
+<value>䘢</value>
+<value>䘣</value>
+<value>䘤</value>
+<value>䘥</value>
+<value>䘦</value>
+<value>䘧</value>
+<value>䘨</value>
+<value>䘩</value>
+<value>䘰</value>
+<value>䘱</value>
+<value>䘲</value>
+<value>䘳</value>
+<value>䘴</value>
+<value>䘵</value>
+<value>䘶</value>
+<value>䘷</value>
+<value>䘸</value>
+<value>䘹</value>
+<value>䙀</value>
+<value>䙁</value>
+<value>䙂</value>
+<value>䙃</value>
+<value>䙄</value>
+<value>䙅</value>
+<value>䙆</value>
+<value>䙇</value>
+<value>䙈</value>
+<value>䙉</value>
+<value>䙐</value>
+<value>䙑</value>
+<value>䙒</value>
+<value>䙓</value>
+<value>䙔</value>
+<value>䙕</value>
+<value>䙖</value>
+<value>䙗</value>
+<value>䙘</value>
+<value>䙙</value>
+<value>䙠</value>
+<value>䙡</value>
+<value>䙢</value>
+<value>䙣</value>
+<value>䙤</value>
+<value>䙥</value>
+<value>䙦</value>
+<value>䙧</value>
+<value>䙨</value>
+<value>䙩</value>
+<value>䙰</value>
+<value>䙱</value>
+<value>䙲</value>
+<value>䙳</value>
+<value>䙴</value>
+<value>䙵</value>
+<value>䙶</value>
+<value>䙷</value>
+<value>䙸</value>
+<value>䙹</value>
+<value>䚀</value>
+<value>䚁</value>
+<value>䚂</value>
+<value>䚃</value>
+<value>䚄</value>
+<value>䚅</value>
+<value>䚆</value>
+<value>䚇</value>
+<value>䚈</value>
+<value>䚉</value>
+<value>䚐</value>
+<value>䚑</value>
+<value>䚒</value>
+<value>䚓</value>
+<value>䚔</value>
+<value>䚕</value>
+<value>䚖</value>
+<value>䚗</value>
+<value>䚘</value>
+<value>䚙</value>
+<value>䜀</value>
+<value>䜁</value>
+<value>䜂</value>
+<value>䜃</value>
+<value>䜄</value>
+<value>䜅</value>
+<value>䜆</value>
+<value>䜇</value>
+<value>䜈</value>
+<value>䜉</value>
+<value>䜐</value>
+<value>䜑</value>
+<value>䜒</value>
+<value>䜓</value>
+<value>䜔</value>
+<value>䜕</value>
+<value>䜖</value>
+<value>䜗</value>
+<value>䜘</value>
+<value>䜙</value>
+<value>䜠</value>
+<value>䜡</value>
+<value>䜢</value>
+<value>䜣</value>
+<value>䜤</value>
+<value>䜥</value>
+<value>䜦</value>
+<value>䜧</value>
+<value>䜨</value>
+<value>䜩</value>
+<value>䜰</value>
+<value>䜱</value>
+<value>䜲</value>
+<value>䜳</value>
+<value>䜴</value>
+<value>䜵</value>
+<value>䜶</value>
+<value>䜷</value>
+<value>䜸</value>
+<value>䜹</value>
+<value>䝀</value>
+<value>䝁</value>
+<value>䝂</value>
+<value>䝃</value>
+<value>䝄</value>
+<value>䝅</value>
+<value>䝆</value>
+<value>䝇</value>
+<value>䝈</value>
+<value>䝉</value>
+<value>䝐</value>
+<value>䝑</value>
+<value>䝒</value>
+<value>䝓</value>
+<value>䝔</value>
+<value>䝕</value>
+<value>䝖</value>
+<value>䝗</value>
+<value>䝘</value>
+<value>䝙</value>
+<value>䝠</value>
+<value>䝡</value>
+<value>䝢</value>
+<value>䝣</value>
+<value>䝤</value>
+<value>䝥</value>
+<value>䝦</value>
+<value>䝧</value>
+<value>䝨</value>
+<value>䝩</value>
+<value>䝰</value>
+<value>䝱</value>
+<value>䝲</value>
+<value>䝳</value>
+<value>䝴</value>
+<value>䝵</value>
+<value>䝶</value>
+<value>䝷</value>
+<value>䝸</value>
+<value>䝹</value>
+<value>䞀</value>
+<value>䞁</value>
+<value>䞂</value>
+<value>䞃</value>
+<value>䞄</value>
+<value>䞅</value>
+<value>䞆</value>
+<value>䞇</value>
+<value>䞈</value>
+<value>䞉</value>
+<value>䞐</value>
+<value>䞑</value>
+<value>䞒</value>
+<value>䞓</value>
+<value>䞔</value>
+<value>䞕</value>
+<value>䞖</value>
+<value>䞗</value>
+<value>䞘</value>
+<value>䞙</value>
+<value>䠀</value>
+<value>䠁</value>
+<value>䠂</value>
+<value>䠃</value>
+<value>䠄</value>
+<value>䠅</value>
+<value>䠆</value>
+<value>䠇</value>
+<value>䠈</value>
+<value>䠉</value>
+<value>䠐</value>
+<value>䠑</value>
+<value>䠒</value>
+<value>䠓</value>
+<value>䠔</value>
+<value>䠕</value>
+<value>䠖</value>
+<value>䠗</value>
+<value>䠘</value>
+<value>䠙</value>
+<value>䠠</value>
+<value>䠡</value>
+<value>䠢</value>
+<value>䠣</value>
+<value>䠤</value>
+<value>䠥</value>
+<value>䠦</value>
+<value>䠧</value>
+<value>䠨</value>
+<value>䠩</value>
+<value>䠰</value>
+<value>䠱</value>
+<value>䠲</value>
+<value>䠳</value>
+<value>䠴</value>
+<value>䠵</value>
+<value>䠶</value>
+<value>䠷</value>
+<value>䠸</value>
+<value>䠹</value>
+<value>䡀</value>
+<value>䡁</value>
+<value>䡂</value>
+<value>䡃</value>
+<value>䡄</value>
+<value>䡅</value>
+<value>䡆</value>
+<value>䡇</value>
+<value>䡈</value>
+<value>䡉</value>
+<value>䡐</value>
+<value>䡑</value>
+<value>䡒</value>
+<value>䡓</value>
+<value>䡔</value>
+<value>䡕</value>
+<value>䡖</value>
+<value>䡗</value>
+<value>䡘</value>
+<value>䡙</value>
+<value>䡠</value>
+<value>䡡</value>
+<value>䡢</value>
+<value>䡣</value>
+<value>䡤</value>
+<value>䡥</value>
+<value>䡦</value>
+<value>䡧</value>
+<value>䡨</value>
+<value>䡩</value>
+<value>䡰</value>
+<value>䡱</value>
+<value>䡲</value>
+<value>䡳</value>
+<value>䡴</value>
+<value>䡵</value>
+<value>䡶</value>
+<value>䡷</value>
+<value>䡸</value>
+<value>䡹</value>
+<value>䢀</value>
+<value>䢁</value>
+<value>䢂</value>
+<value>䢃</value>
+<value>䢄</value>
+<value>䢅</value>
+<value>䢆</value>
+<value>䢇</value>
+<value>䢈</value>
+<value>䢉</value>
+<value>䢐</value>
+<value>䢑</value>
+<value>䢒</value>
+<value>䢓</value>
+<value>䢔</value>
+<value>䢕</value>
+<value>䢖</value>
+<value>䢗</value>
+<value>䢘</value>
+<value>䢙</value>
+<value>䤀</value>
+<value>䤁</value>
+<value>䤂</value>
+<value>䤃</value>
+<value>䤄</value>
+<value>䤅</value>
+<value>䤆</value>
+<value>䤇</value>
+<value>䤈</value>
+<value>䤉</value>
+<value>䤐</value>
+<value>䤑</value>
+<value>䤒</value>
+<value>䤓</value>
+<value>䤔</value>
+<value>䤕</value>
+<value>䤖</value>
+<value>䤗</value>
+<value>䤘</value>
+<value>䤙</value>
+<value>䤠</value>
+<value>䤡</value>
+<value>䤢</value>
+<value>䤣</value>
+<value>䤤</value>
+<value>䤥</value>
+<value>䤦</value>
+<value>䤧</value>
+<value>䤨</value>
+<value>䤩</value>
+<value>䤰</value>
+<value>䤱</value>
+<value>䤲</value>
+<value>䤳</value>
+<value>䤴</value>
+<value>䤵</value>
+<value>䤶</value>
+<value>䤷</value>
+<value>䤸</value>
+<value>䤹</value>
+<value>䥀</value>
+<value>䥁</value>
+<value>䥂</value>
+<value>䥃</value>
+<value>䥄</value>
+<value>䥅</value>
+<value>䥆</value>
+<value>䥇</value>
+<value>䥈</value>
+<value>䥉</value>
+<value>䥐</value>
+<value>䥑</value>
+<value>䥒</value>
+<value>䥓</value>
+<value>䥔</value>
+<value>䥕</value>
+<value>䥖</value>
+<value>䥗</value>
+<value>䥘</value>
+<value>䥙</value>
+<value>䥠</value>
+<value>䥡</value>
+<value>䥢</value>
+<value>䥣</value>
+<value>䥤</value>
+<value>䥥</value>
+<value>䥦</value>
+<value>䥧</value>
+<value>䥨</value>
+<value>䥩</value>
+<value>䥰</value>
+<value>䥱</value>
+<value>䥲</value>
+<value>䥳</value>
+<value>䥴</value>
+<value>䥵</value>
+<value>䥶</value>
+<value>䥷</value>
+<value>䥸</value>
+<value>䥹</value>
+<value>䦀</value>
+<value>䦁</value>
+<value>䦂</value>
+<value>䦃</value>
+<value>䦄</value>
+<value>䦅</value>
+<value>䦆</value>
+<value>䦇</value>
+<value>䦈</value>
+<value>䦉</value>
+<value>䦐</value>
+<value>䦑</value>
+<value>䦒</value>
+<value>䦓</value>
+<value>䦔</value>
+<value>䦕</value>
+<value>䦖</value>
+<value>䦗</value>
+<value>䦘</value>
+<value>䦙</value>
+<value>倀</value>
+<value>倁</value>
+<value>倂</value>
+<value>倃</value>
+<value>倄</value>
+<value>倅</value>
+<value>倆</value>
+<value>倇</value>
+<value>倈</value>
+<value>倉</value>
+<value>倐</value>
+<value>們</value>
+<value>倒</value>
+<value>倓</value>
+<value>倔</value>
+<value>倕</value>
+<value>倖</value>
+<value>倗</value>
+<value>倘</value>
+<value>候</value>
+<value>倠</value>
+<value>倡</value>
+<value>倢</value>
+<value>倣</value>
+<value>値</value>
+<value>倥</value>
+<value>倦</value>
+<value>倧</value>
+<value>倨</value>
+<value>倩</value>
+<value>倰</value>
+<value>倱</value>
+<value>倲</value>
+<value>倳</value>
+<value>倴</value>
+<value>倵</value>
+<value>倶</value>
+<value>倷</value>
+<value>倸</value>
+<value>倹</value>
+<value>偀</value>
+<value>偁</value>
+<value>偂</value>
+<value>偃</value>
+<value>偄</value>
+<value>偅</value>
+<value>偆</value>
+<value>假</value>
+<value>偈</value>
+<value>偉</value>
+<value>偐</value>
+<value>偑</value>
+<value>偒</value>
+<value>偓</value>
+<value>偔</value>
+<value>偕</value>
+<value>偖</value>
+<value>偗</value>
+<value>偘</value>
+<value>偙</value>
+<value>偠</value>
+<value>偡</value>
+<value>偢</value>
+<value>偣</value>
+<value>偤</value>
+<value>健</value>
+<value>偦</value>
+<value>偧</value>
+<value>偨</value>
+<value>偩</value>
+<value>偰</value>
+<value>偱</value>
+<value>偲</value>
+<value>偳</value>
+<value>側</value>
+<value>偵</value>
+<value>偶</value>
+<value>偷</value>
+<value>偸</value>
+<value>偹</value>
+<value>傀</value>
+<value>傁</value>
+<value>傂</value>
+<value>傃</value>
+<value>傄</value>
+<value>傅</value>
+<value>傆</value>
+<value>傇</value>
+<value>傈</value>
+<value>傉</value>
+<value>傐</value>
+<value>傑</value>
+<value>傒</value>
+<value>傓</value>
+<value>傔</value>
+<value>傕</value>
+<value>傖</value>
+<value>傗</value>
+<value>傘</value>
+<value>備</value>
+<value>儀</value>
+<value>儁</value>
+<value>儂</value>
+<value>儃</value>
+<value>億</value>
+<value>儅</value>
+<value>儆</value>
+<value>儇</value>
+<value>儈</value>
+<value>儉</value>
+<value>儐</value>
+<value>儑</value>
+<value>儒</value>
+<value>儓</value>
+<value>儔</value>
+<value>儕</value>
+<value>儖</value>
+<value>儗</value>
+<value>儘</value>
+<value>儙</value>
+<value>儠</value>
+<value>儡</value>
+<value>儢</value>
+<value>儣</value>
+<value>儤</value>
+<value>儥</value>
+<value>儦</value>
+<value>儧</value>
+<value>儨</value>
+<value>儩</value>
+<value>儰</value>
+<value>儱</value>
+<value>儲</value>
+<value>儳</value>
+<value>儴</value>
+<value>儵</value>
+<value>儶</value>
+<value>儷</value>
+<value>儸</value>
+<value>儹</value>
+<value>兀</value>
+<value>允</value>
+<value>兂</value>
+<value>元</value>
+<value>兄</value>
+<value>充</value>
+<value>兆</value>
+<value>兇</value>
+<value>先</value>
+<value>光</value>
+<value>児</value>
+<value>兑</value>
+<value>兒</value>
+<value>兓</value>
+<value>兔</value>
+<value>兕</value>
+<value>兖</value>
+<value>兗</value>
+<value>兘</value>
+<value>兙</value>
+<value>兠</value>
+<value>兡</value>
+<value>兢</value>
+<value>兣</value>
+<value>兤</value>
+<value>入</value>
+<value>兦</value>
+<value>內</value>
+<value>全</value>
+<value>兩</value>
+<value>兰</value>
+<value>共</value>
+<value>兲</value>
+<value>关</value>
+<value>兴</value>
+<value>兵</value>
+<value>其</value>
+<value>具</value>
+<value>典</value>
+<value>兹</value>
+<value>冀</value>
+<value>冁</value>
+<value>冂</value>
+<value>冃</value>
+<value>冄</value>
+<value>内</value>
+<value>円</value>
+<value>冇</value>
+<value>冈</value>
+<value>冉</value>
+<value>冐</value>
+<value>冑</value>
+<value>冒</value>
+<value>冓</value>
+<value>冔</value>
+<value>冕</value>
+<value>冖</value>
+<value>冗</value>
+<value>冘</value>
+<value>写</value>
+<value>刀</value>
+<value>刁</value>
+<value>刂</value>
+<value>刃</value>
+<value>刄</value>
+<value>刅</value>
+<value>分</value>
+<value>切</value>
+<value>刈</value>
+<value>刉</value>
+<value>刐</value>
+<value>刑</value>
+<value>划</value>
+<value>刓</value>
+<value>刔</value>
+<value>刕</value>
+<value>刖</value>
+<value>列</value>
+<value>刘</value>
+<value>则</value>
+<value>删</value>
+<value>刡</value>
+<value>刢</value>
+<value>刣</value>
+<value>判</value>
+<value>別</value>
+<value>刦</value>
+<value>刧</value>
+<value>刨</value>
+<value>利</value>
+<value>到</value>
+<value>刱</value>
+<value>刲</value>
+<value>刳</value>
+<value>刴</value>
+<value>刵</value>
+<value>制</value>
+<value>刷</value>
+<value>券</value>
+<value>刹</value>
+<value>剀</value>
+<value>剁</value>
+<value>剂</value>
+<value>剃</value>
+<value>剄</value>
+<value>剅</value>
+<value>剆</value>
+<value>則</value>
+<value>剈</value>
+<value>剉</value>
+<value>剐</value>
+<value>剑</value>
+<value>剒</value>
+<value>剓</value>
+<value>剔</value>
+<value>剕</value>
+<value>剖</value>
+<value>剗</value>
+<value>剘</value>
+<value>剙</value>
+<value>剠</value>
+<value>剡</value>
+<value>剢</value>
+<value>剣</value>
+<value>剤</value>
+<value>剥</value>
+<value>剦</value>
+<value>剧</value>
+<value>剨</value>
+<value>剩</value>
+<value>剰</value>
+<value>剱</value>
+<value>割</value>
+<value>剳</value>
+<value>剴</value>
+<value>創</value>
+<value>剶</value>
+<value>剷</value>
+<value>剸</value>
+<value>剹</value>
+<value>劀</value>
+<value>劁</value>
+<value>劂</value>
+<value>劃</value>
+<value>劄</value>
+<value>劅</value>
+<value>劆</value>
+<value>劇</value>
+<value>劈</value>
+<value>劉</value>
+<value>劐</value>
+<value>劑</value>
+<value>劒</value>
+<value>劓</value>
+<value>劔</value>
+<value>劕</value>
+<value>劖</value>
+<value>劗</value>
+<value>劘</value>
+<value>劙</value>
+<value>匀</value>
+<value>匁</value>
+<value>匂</value>
+<value>匃</value>
+<value>匄</value>
+<value>包</value>
+<value>匆</value>
+<value>匇</value>
+<value>匈</value>
+<value>匉</value>
+<value>匐</value>
+<value>匑</value>
+<value>匒</value>
+<value>匓</value>
+<value>匔</value>
+<value>匕</value>
+<value>化</value>
+<value>北</value>
+<value>匘</value>
+<value>匙</value>
+<value>匠</value>
+<value>匡</value>
+<value>匢</value>
+<value>匣</value>
+<value>匤</value>
+<value>匥</value>
+<value>匦</value>
+<value>匧</value>
+<value>匨</value>
+<value>匩</value>
+<value>匰</value>
+<value>匱</value>
+<value>匲</value>
+<value>匳</value>
+<value>匴</value>
+<value>匵</value>
+<value>匶</value>
+<value>匷</value>
+<value>匸</value>
+<value>匹</value>
+<value>區</value>
+<value>十</value>
+<value>卂</value>
+<value>千</value>
+<value>卄</value>
+<value>卅</value>
+<value>卆</value>
+<value>升</value>
+<value>午</value>
+<value>卉</value>
+<value>卐</value>
+<value>卑</value>
+<value>卒</value>
+<value>卓</value>
+<value>協</value>
+<value>单</value>
+<value>卖</value>
+<value>南</value>
+<value>単</value>
+<value>卙</value>
+<value>占</value>
+<value>卡</value>
+<value>卢</value>
+<value>卣</value>
+<value>卤</value>
+<value>卥</value>
+<value>卦</value>
+<value>卧</value>
+<value>卨</value>
+<value>卩</value>
+<value>印</value>
+<value>危</value>
+<value>卲</value>
+<value>即</value>
+<value>却</value>
+<value>卵</value>
+<value>卶</value>
+<value>卷</value>
+<value>卸</value>
+<value>卹</value>
+<value>厀</value>
+<value>厁</value>
+<value>厂</value>
+<value>厃</value>
+<value>厄</value>
+<value>厅</value>
+<value>历</value>
+<value>厇</value>
+<value>厈</value>
+<value>厉</value>
+<value>厐</value>
+<value>厑</value>
+<value>厒</value>
+<value>厓</value>
+<value>厔</value>
+<value>厕</value>
+<value>厖</value>
+<value>厗</value>
+<value>厘</value>
+<value>厙</value>
+<value>吀</value>
+<value>吁</value>
+<value>吂</value>
+<value>吃</value>
+<value>各</value>
+<value>吅</value>
+<value>吆</value>
+<value>吇</value>
+<value>合</value>
+<value>吉</value>
+<value>吐</value>
+<value>向</value>
+<value>吒</value>
+<value>吓</value>
+<value>吔</value>
+<value>吕</value>
+<value>吖</value>
+<value>吗</value>
+<value>吘</value>
+<value>吙</value>
+<value>吠</value>
+<value>吡</value>
+<value>吢</value>
+<value>吣</value>
+<value>吤</value>
+<value>吥</value>
+<value>否</value>
+<value>吧</value>
+<value>吨</value>
+<value>吩</value>
+<value>吰</value>
+<value>吱</value>
+<value>吲</value>
+<value>吳</value>
+<value>吴</value>
+<value>吵</value>
+<value>吶</value>
+<value>吷</value>
+<value>吸</value>
+<value>吹</value>
+<value>呀</value>
+<value>呁</value>
+<value>呂</value>
+<value>呃</value>
+<value>呄</value>
+<value>呅</value>
+<value>呆</value>
+<value>呇</value>
+<value>呈</value>
+<value>呉</value>
+<value>呐</value>
+<value>呑</value>
+<value>呒</value>
+<value>呓</value>
+<value>呔</value>
+<value>呕</value>
+<value>呖</value>
+<value>呗</value>
+<value>员</value>
+<value>呙</value>
+<value>呠</value>
+<value>呡</value>
+<value>呢</value>
+<value>呣</value>
+<value>呤</value>
+<value>呥</value>
+<value>呦</value>
+<value>呧</value>
+<value>周</value>
+<value>呩</value>
+<value>呰</value>
+<value>呱</value>
+<value>呲</value>
+<value>味</value>
+<value>呴</value>
+<value>呵</value>
+<value>呶</value>
+<value>呷</value>
+<value>呸</value>
+<value>呹</value>
+<value>咀</value>
+<value>咁</value>
+<value>咂</value>
+<value>咃</value>
+<value>咄</value>
+<value>咅</value>
+<value>咆</value>
+<value>咇</value>
+<value>咈</value>
+<value>咉</value>
+<value>咐</value>
+<value>咑</value>
+<value>咒</value>
+<value>咓</value>
+<value>咔</value>
+<value>咕</value>
+<value>咖</value>
+<value>咗</value>
+<value>咘</value>
+<value>咙</value>
+<value>唀</value>
+<value>唁</value>
+<value>唂</value>
+<value>唃</value>
+<value>唄</value>
+<value>唅</value>
+<value>唆</value>
+<value>唇</value>
+<value>唈</value>
+<value>唉</value>
+<value>唐</value>
+<value>唑</value>
+<value>唒</value>
+<value>唓</value>
+<value>唔</value>
+<value>唕</value>
+<value>唖</value>
+<value>唗</value>
+<value>唘</value>
+<value>唙</value>
+<value>唠</value>
+<value>唡</value>
+<value>唢</value>
+<value>唣</value>
+<value>唤</value>
+<value>唥</value>
+<value>唦</value>
+<value>唧</value>
+<value>唨</value>
+<value>唩</value>
+<value>唰</value>
+<value>唱</value>
+<value>唲</value>
+<value>唳</value>
+<value>唴</value>
+<value>唵</value>
+<value>唶</value>
+<value>唷</value>
+<value>唸</value>
+<value>唹</value>
+<value>啀</value>
+<value>啁</value>
+<value>啂</value>
+<value>啃</value>
+<value>啄</value>
+<value>啅</value>
+<value>商</value>
+<value>啇</value>
+<value>啈</value>
+<value>啉</value>
+<value>啐</value>
+<value>啑</value>
+<value>啒</value>
+<value>啓</value>
+<value>啔</value>
+<value>啕</value>
+<value>啖</value>
+<value>啗</value>
+<value>啘</value>
+<value>啙</value>
+<value>啠</value>
+<value>啡</value>
+<value>啢</value>
+<value>啣</value>
+<value>啤</value>
+<value>啥</value>
+<value>啦</value>
+<value>啧</value>
+<value>啨</value>
+<value>啩</value>
+<value>啰</value>
+<value>啱</value>
+<value>啲</value>
+<value>啳</value>
+<value>啴</value>
+<value>啵</value>
+<value>啶</value>
+<value>啷</value>
+<value>啸</value>
+<value>啹</value>
+<value>喀</value>
+<value>喁</value>
+<value>喂</value>
+<value>喃</value>
+<value>善</value>
+<value>喅</value>
+<value>喆</value>
+<value>喇</value>
+<value>喈</value>
+<value>喉</value>
+<value>喐</value>
+<value>喑</value>
+<value>喒</value>
+<value>喓</value>
+<value>喔</value>
+<value>喕</value>
+<value>喖</value>
+<value>喗</value>
+<value>喘</value>
+<value>喙</value>
+<value>嘀</value>
+<value>嘁</value>
+<value>嘂</value>
+<value>嘃</value>
+<value>嘄</value>
+<value>嘅</value>
+<value>嘆</value>
+<value>嘇</value>
+<value>嘈</value>
+<value>嘉</value>
+<value>嘐</value>
+<value>嘑</value>
+<value>嘒</value>
+<value>嘓</value>
+<value>嘔</value>
+<value>嘕</value>
+<value>嘖</value>
+<value>嘗</value>
+<value>嘘</value>
+<value>嘙</value>
+<value>嘠</value>
+<value>嘡</value>
+<value>嘢</value>
+<value>嘣</value>
+<value>嘤</value>
+<value>嘥</value>
+<value>嘦</value>
+<value>嘧</value>
+<value>嘨</value>
+<value>嘩</value>
+<value>嘰</value>
+<value>嘱</value>
+<value>嘲</value>
+<value>嘳</value>
+<value>嘴</value>
+<value>嘵</value>
+<value>嘶</value>
+<value>嘷</value>
+<value>嘸</value>
+<value>嘹</value>
+<value>噀</value>
+<value>噁</value>
+<value>噂</value>
+<value>噃</value>
+<value>噄</value>
+<value>噅</value>
+<value>噆</value>
+<value>噇</value>
+<value>噈</value>
+<value>噉</value>
+<value>噐</value>
+<value>噑</value>
+<value>噒</value>
+<value>噓</value>
+<value>噔</value>
+<value>噕</value>
+<value>噖</value>
+<value>噗</value>
+<value>噘</value>
+<value>噙</value>
+<value>噠</value>
+<value>噡</value>
+<value>噢</value>
+<value>噣</value>
+<value>噤</value>
+<value>噥</value>
+<value>噦</value>
+<value>噧</value>
+<value>器</value>
+<value>噩</value>
+<value>噰</value>
+<value>噱</value>
+<value>噲</value>
+<value>噳</value>
+<value>噴</value>
+<value>噵</value>
+<value>噶</value>
+<value>噷</value>
+<value>噸</value>
+<value>噹</value>
+<value>嚀</value>
+<value>嚁</value>
+<value>嚂</value>
+<value>嚃</value>
+<value>嚄</value>
+<value>嚅</value>
+<value>嚆</value>
+<value>嚇</value>
+<value>嚈</value>
+<value>嚉</value>
+<value>嚐</value>
+<value>嚑</value>
+<value>嚒</value>
+<value>嚓</value>
+<value>嚔</value>
+<value>嚕</value>
+<value>嚖</value>
+<value>嚗</value>
+<value>嚘</value>
+<value>嚙</value>
+<value>圀</value>
+<value>圁</value>
+<value>圂</value>
+<value>圃</value>
+<value>圄</value>
+<value>圅</value>
+<value>圆</value>
+<value>圇</value>
+<value>圈</value>
+<value>圉</value>
+<value>圐</value>
+<value>圑</value>
+<value>園</value>
+<value>圓</value>
+<value>圔</value>
+<value>圕</value>
+<value>圖</value>
+<value>圗</value>
+<value>團</value>
+<value>圙</value>
+<value>圠</value>
+<value>圡</value>
+<value>圢</value>
+<value>圣</value>
+<value>圤</value>
+<value>圥</value>
+<value>圦</value>
+<value>圧</value>
+<value>在</value>
+<value>圩</value>
+<value>地</value>
+<value>圱</value>
+<value>圲</value>
+<value>圳</value>
+<value>圴</value>
+<value>圵</value>
+<value>圶</value>
+<value>圷</value>
+<value>圸</value>
+<value>圹</value>
+<value>址</value>
+<value>坁</value>
+<value>坂</value>
+<value>坃</value>
+<value>坄</value>
+<value>坅</value>
+<value>坆</value>
+<value>均</value>
+<value>坈</value>
+<value>坉</value>
+<value>坐</value>
+<value>坑</value>
+<value>坒</value>
+<value>坓</value>
+<value>坔</value>
+<value>坕</value>
+<value>坖</value>
+<value>块</value>
+<value>坘</value>
+<value>坙</value>
+<value>坠</value>
+<value>坡</value>
+<value>坢</value>
+<value>坣</value>
+<value>坤</value>
+<value>坥</value>
+<value>坦</value>
+<value>坧</value>
+<value>坨</value>
+<value>坩</value>
+<value>坰</value>
+<value>坱</value>
+<value>坲</value>
+<value>坳</value>
+<value>坴</value>
+<value>坵</value>
+<value>坶</value>
+<value>坷</value>
+<value>坸</value>
+<value>坹</value>
+<value>垀</value>
+<value>垁</value>
+<value>垂</value>
+<value>垃</value>
+<value>垄</value>
+<value>垅</value>
+<value>垆</value>
+<value>垇</value>
+<value>垈</value>
+<value>垉</value>
+<value>垐</value>
+<value>垑</value>
+<value>垒</value>
+<value>垓</value>
+<value>垔</value>
+<value>垕</value>
+<value>垖</value>
+<value>垗</value>
+<value>垘</value>
+<value>垙</value>
+<value>堀</value>
+<value>堁</value>
+<value>堂</value>
+<value>堃</value>
+<value>堄</value>
+<value>堅</value>
+<value>堆</value>
+<value>堇</value>
+<value>堈</value>
+<value>堉</value>
+<value>堐</value>
+<value>堑</value>
+<value>堒</value>
+<value>堓</value>
+<value>堔</value>
+<value>堕</value>
+<value>堖</value>
+<value>堗</value>
+<value>堘</value>
+<value>堙</value>
+<value>堠</value>
+<value>堡</value>
+<value>堢</value>
+<value>堣</value>
+<value>堤</value>
+<value>堥</value>
+<value>堦</value>
+<value>堧</value>
+<value>堨</value>
+<value>堩</value>
+<value>堰</value>
+<value>報</value>
+<value>堲</value>
+<value>堳</value>
+<value>場</value>
+<value>堵</value>
+<value>堶</value>
+<value>堷</value>
+<value>堸</value>
+<value>堹</value>
+<value>塀</value>
+<value>塁</value>
+<value>塂</value>
+<value>塃</value>
+<value>塄</value>
+<value>塅</value>
+<value>塆</value>
+<value>塇</value>
+<value>塈</value>
+<value>塉</value>
+<value>塐</value>
+<value>塑</value>
+<value>塒</value>
+<value>塓</value>
+<value>塔</value>
+<value>塕</value>
+<value>塖</value>
+<value>塗</value>
+<value>塘</value>
+<value>塙</value>
+<value>塠</value>
+<value>塡</value>
+<value>塢</value>
+<value>塣</value>
+<value>塤</value>
+<value>塥</value>
+<value>塦</value>
+<value>塧</value>
+<value>塨</value>
+<value>塩</value>
+<value>塰</value>
+<value>塱</value>
+<value>塲</value>
+<value>塳</value>
+<value>塴</value>
+<value>塵</value>
+<value>塶</value>
+<value>塷</value>
+<value>塸</value>
+<value>塹</value>
+<value>墀</value>
+<value>墁</value>
+<value>墂</value>
+<value>境</value>
+<value>墄</value>
+<value>墅</value>
+<value>墆</value>
+<value>墇</value>
+<value>墈</value>
+<value>墉</value>
+<value>墐</value>
+<value>墑</value>
+<value>墒</value>
+<value>墓</value>
+<value>墔</value>
+<value>墕</value>
+<value>墖</value>
+<value>増</value>
+<value>墘</value>
+<value>墙</value>
+<value>夀</value>
+<value>夁</value>
+<value>夂</value>
+<value>夃</value>
+<value>处</value>
+<value>夅</value>
+<value>夆</value>
+<value>备</value>
+<value>夈</value>
+<value>変</value>
+<value>夐</value>
+<value>夑</value>
+<value>夒</value>
+<value>夓</value>
+<value>夔</value>
+<value>夕</value>
+<value>外</value>
+<value>夗</value>
+<value>夘</value>
+<value>夙</value>
+<value>夠</value>
+<value>夡</value>
+<value>夢</value>
+<value>夣</value>
+<value>夤</value>
+<value>夥</value>
+<value>夦</value>
+<value>大</value>
+<value>夨</value>
+<value>天</value>
+<value>夰</value>
+<value>失</value>
+<value>夲</value>
+<value>夳</value>
+<value>头</value>
+<value>夵</value>
+<value>夶</value>
+<value>夷</value>
+<value>夸</value>
+<value>夹</value>
+<value>奀</value>
+<value>奁</value>
+<value>奂</value>
+<value>奃</value>
+<value>奄</value>
+<value>奅</value>
+<value>奆</value>
+<value>奇</value>
+<value>奈</value>
+<value>奉</value>
+<value>奐</value>
+<value>契</value>
+<value>奒</value>
+<value>奓</value>
+<value>奔</value>
+<value>奕</value>
+<value>奖</value>
+<value>套</value>
+<value>奘</value>
+<value>奙</value>
+<value>奠</value>
+<value>奡</value>
+<value>奢</value>
+<value>奣</value>
+<value>奤</value>
+<value>奥</value>
+<value>奦</value>
+<value>奧</value>
+<value>奨</value>
+<value>奩</value>
+<value>奰</value>
+<value>奱</value>
+<value>奲</value>
+<value>女</value>
+<value>奴</value>
+<value>奵</value>
+<value>奶</value>
+<value>奷</value>
+<value>奸</value>
+<value>她</value>
+<value>妀</value>
+<value>妁</value>
+<value>如</value>
+<value>妃</value>
+<value>妄</value>
+<value>妅</value>
+<value>妆</value>
+<value>妇</value>
+<value>妈</value>
+<value>妉</value>
+<value>妐</value>
+<value>妑</value>
+<value>妒</value>
+<value>妓</value>
+<value>妔</value>
+<value>妕</value>
+<value>妖</value>
+<value>妗</value>
+<value>妘</value>
+<value>妙</value>
+<value>怀</value>
+<value>态</value>
+<value>怂</value>
+<value>怃</value>
+<value>怄</value>
+<value>怅</value>
+<value>怆</value>
+<value>怇</value>
+<value>怈</value>
+<value>怉</value>
+<value>怐</value>
+<value>怑</value>
+<value>怒</value>
+<value>怓</value>
+<value>怔</value>
+<value>怕</value>
+<value>怖</value>
+<value>怗</value>
+<value>怘</value>
+<value>怙</value>
+<value>怠</value>
+<value>怡</value>
+<value>怢</value>
+<value>怣</value>
+<value>怤</value>
+<value>急</value>
+<value>怦</value>
+<value>性</value>
+<value>怨</value>
+<value>怩</value>
+<value>怰</value>
+<value>怱</value>
+<value>怲</value>
+<value>怳</value>
+<value>怴</value>
+<value>怵</value>
+<value>怶</value>
+<value>怷</value>
+<value>怸</value>
+<value>怹</value>
+<value>恀</value>
+<value>恁</value>
+<value>恂</value>
+<value>恃</value>
+<value>恄</value>
+<value>恅</value>
+<value>恆</value>
+<value>恇</value>
+<value>恈</value>
+<value>恉</value>
+<value>恐</value>
+<value>恑</value>
+<value>恒</value>
+<value>恓</value>
+<value>恔</value>
+<value>恕</value>
+<value>恖</value>
+<value>恗</value>
+<value>恘</value>
+<value>恙</value>
+<value>恠</value>
+<value>恡</value>
+<value>恢</value>
+<value>恣</value>
+<value>恤</value>
+<value>恥</value>
+<value>恦</value>
+<value>恧</value>
+<value>恨</value>
+<value>恩</value>
+<value>恰</value>
+<value>恱</value>
+<value>恲</value>
+<value>恳</value>
+<value>恴</value>
+<value>恵</value>
+<value>恶</value>
+<value>恷</value>
+<value>恸</value>
+<value>恹</value>
+<value>悀</value>
+<value>悁</value>
+<value>悂</value>
+<value>悃</value>
+<value>悄</value>
+<value>悅</value>
+<value>悆</value>
+<value>悇</value>
+<value>悈</value>
+<value>悉</value>
+<value>悐</value>
+<value>悑</value>
+<value>悒</value>
+<value>悓</value>
+<value>悔</value>
+<value>悕</value>
+<value>悖</value>
+<value>悗</value>
+<value>悘</value>
+<value>悙</value>
+<value>愀</value>
+<value>愁</value>
+<value>愂</value>
+<value>愃</value>
+<value>愄</value>
+<value>愅</value>
+<value>愆</value>
+<value>愇</value>
+<value>愈</value>
+<value>愉</value>
+<value>愐</value>
+<value>愑</value>
+<value>愒</value>
+<value>愓</value>
+<value>愔</value>
+<value>愕</value>
+<value>愖</value>
+<value>愗</value>
+<value>愘</value>
+<value>愙</value>
+<value>愠</value>
+<value>愡</value>
+<value>愢</value>
+<value>愣</value>
+<value>愤</value>
+<value>愥</value>
+<value>愦</value>
+<value>愧</value>
+<value>愨</value>
+<value>愩</value>
+<value>愰</value>
+<value>愱</value>
+<value>愲</value>
+<value>愳</value>
+<value>愴</value>
+<value>愵</value>
+<value>愶</value>
+<value>愷</value>
+<value>愸</value>
+<value>愹</value>
+<value>慀</value>
+<value>慁</value>
+<value>慂</value>
+<value>慃</value>
+<value>慄</value>
+<value>慅</value>
+<value>慆</value>
+<value>慇</value>
+<value>慈</value>
+<value>慉</value>
+<value>慐</value>
+<value>慑</value>
+<value>慒</value>
+<value>慓</value>
+<value>慔</value>
+<value>慕</value>
+<value>慖</value>
+<value>慗</value>
+<value>慘</value>
+<value>慙</value>
+<value>慠</value>
+<value>慡</value>
+<value>慢</value>
+<value>慣</value>
+<value>慤</value>
+<value>慥</value>
+<value>慦</value>
+<value>慧</value>
+<value>慨</value>
+<value>慩</value>
+<value>慰</value>
+<value>慱</value>
+<value>慲</value>
+<value>慳</value>
+<value>慴</value>
+<value>慵</value>
+<value>慶</value>
+<value>慷</value>
+<value>慸</value>
+<value>慹</value>
+<value>憀</value>
+<value>憁</value>
+<value>憂</value>
+<value>憃</value>
+<value>憄</value>
+<value>憅</value>
+<value>憆</value>
+<value>憇</value>
+<value>憈</value>
+<value>憉</value>
+<value>憐</value>
+<value>憑</value>
+<value>憒</value>
+<value>憓</value>
+<value>憔</value>
+<value>憕</value>
+<value>憖</value>
+<value>憗</value>
+<value>憘</value>
+<value>憙</value>
+<value>戀</value>
+<value>戁</value>
+<value>戂</value>
+<value>戃</value>
+<value>戄</value>
+<value>戅</value>
+<value>戆</value>
+<value>戇</value>
+<value>戈</value>
+<value>戉</value>
+<value>成</value>
+<value>我</value>
+<value>戒</value>
+<value>戓</value>
+<value>戔</value>
+<value>戕</value>
+<value>或</value>
+<value>戗</value>
+<value>战</value>
+<value>戙</value>
+<value>戠</value>
+<value>戡</value>
+<value>戢</value>
+<value>戣</value>
+<value>戤</value>
+<value>戥</value>
+<value>戦</value>
+<value>戧</value>
+<value>戨</value>
+<value>戩</value>
+<value>戰</value>
+<value>戱</value>
+<value>戲</value>
+<value>戳</value>
+<value>戴</value>
+<value>戵</value>
+<value>戶</value>
+<value>户</value>
+<value>戸</value>
+<value>戹</value>
+<value>所</value>
+<value>扁</value>
+<value>扂</value>
+<value>扃</value>
+<value>扄</value>
+<value>扅</value>
+<value>扆</value>
+<value>扇</value>
+<value>扈</value>
+<value>扉</value>
+<value>扐</value>
+<value>扑</value>
+<value>扒</value>
+<value>打</value>
+<value>扔</value>
+<value>払</value>
+<value>扖</value>
+<value>扗</value>
+<value>托</value>
+<value>扙</value>
+<value>扠</value>
+<value>扡</value>
+<value>扢</value>
+<value>扣</value>
+<value>扤</value>
+<value>扥</value>
+<value>扦</value>
+<value>执</value>
+<value>扨</value>
+<value>扩</value>
+<value>扰</value>
+<value>扱</value>
+<value>扲</value>
+<value>扳</value>
+<value>扴</value>
+<value>扵</value>
+<value>扶</value>
+<value>扷</value>
+<value>扸</value>
+<value>批</value>
+<value>技</value>
+<value>抁</value>
+<value>抂</value>
+<value>抃</value>
+<value>抄</value>
+<value>抅</value>
+<value>抆</value>
+<value>抇</value>
+<value>抈</value>
+<value>抉</value>
+<value>抐</value>
+<value>抑</value>
+<value>抒</value>
+<value>抓</value>
+<value>抔</value>
+<value>投</value>
+<value>抖</value>
+<value>抗</value>
+<value>折</value>
+<value>抙</value>
+<value>挀</value>
+<value>持</value>
+<value>挂</value>
+<value>挃</value>
+<value>挄</value>
+<value>挅</value>
+<value>挆</value>
+<value>指</value>
+<value>挈</value>
+<value>按</value>
+<value>挐</value>
+<value>挑</value>
+<value>挒</value>
+<value>挓</value>
+<value>挔</value>
+<value>挕</value>
+<value>挖</value>
+<value>挗</value>
+<value>挘</value>
+<value>挙</value>
+<value>挠</value>
+<value>挡</value>
+<value>挢</value>
+<value>挣</value>
+<value>挤</value>
+<value>挥</value>
+<value>挦</value>
+<value>挧</value>
+<value>挨</value>
+<value>挩</value>
+<value>挰</value>
+<value>挱</value>
+<value>挲</value>
+<value>挳</value>
+<value>挴</value>
+<value>挵</value>
+<value>挶</value>
+<value>挷</value>
+<value>挸</value>
+<value>挹</value>
+<value>捀</value>
+<value>捁</value>
+<value>捂</value>
+<value>捃</value>
+<value>捄</value>
+<value>捅</value>
+<value>捆</value>
+<value>捇</value>
+<value>捈</value>
+<value>捉</value>
+<value>捐</value>
+<value>捑</value>
+<value>捒</value>
+<value>捓</value>
+<value>捔</value>
+<value>捕</value>
+<value>捖</value>
+<value>捗</value>
+<value>捘</value>
+<value>捙</value>
+<value>捠</value>
+<value>捡</value>
+<value>换</value>
+<value>捣</value>
+<value>捤</value>
+<value>捥</value>
+<value>捦</value>
+<value>捧</value>
+<value>捨</value>
+<value>捩</value>
+<value>捰</value>
+<value>捱</value>
+<value>捲</value>
+<value>捳</value>
+<value>捴</value>
+<value>捵</value>
+<value>捶</value>
+<value>捷</value>
+<value>捸</value>
+<value>捹</value>
+<value>掀</value>
+<value>掁</value>
+<value>掂</value>
+<value>掃</value>
+<value>掄</value>
+<value>掅</value>
+<value>掆</value>
+<value>掇</value>
+<value>授</value>
+<value>掉</value>
+<value>掐</value>
+<value>掑</value>
+<value>排</value>
+<value>掓</value>
+<value>掔</value>
+<value>掕</value>
+<value>掖</value>
+<value>掗</value>
+<value>掘</value>
+<value>掙</value>
+<value>搀</value>
+<value>搁</value>
+<value>搂</value>
+<value>搃</value>
+<value>搄</value>
+<value>搅</value>
+<value>搆</value>
+<value>搇</value>
+<value>搈</value>
+<value>搉</value>
+<value>搐</value>
+<value>搑</value>
+<value>搒</value>
+<value>搓</value>
+<value>搔</value>
+<value>搕</value>
+<value>搖</value>
+<value>搗</value>
+<value>搘</value>
+<value>搙</value>
+<value>搠</value>
+<value>搡</value>
+<value>搢</value>
+<value>搣</value>
+<value>搤</value>
+<value>搥</value>
+<value>搦</value>
+<value>搧</value>
+<value>搨</value>
+<value>搩</value>
+<value>搰</value>
+<value>搱</value>
+<value>搲</value>
+<value>搳</value>
+<value>搴</value>
+<value>搵</value>
+<value>搶</value>
+<value>搷</value>
+<value>搸</value>
+<value>搹</value>
+<value>摀</value>
+<value>摁</value>
+<value>摂</value>
+<value>摃</value>
+<value>摄</value>
+<value>摅</value>
+<value>摆</value>
+<value>摇</value>
+<value>摈</value>
+<value>摉</value>
+<value>摐</value>
+<value>摑</value>
+<value>摒</value>
+<value>摓</value>
+<value>摔</value>
+<value>摕</value>
+<value>摖</value>
+<value>摗</value>
+<value>摘</value>
+<value>摙</value>
+<value>摠</value>
+<value>摡</value>
+<value>摢</value>
+<value>摣</value>
+<value>摤</value>
+<value>摥</value>
+<value>摦</value>
+<value>摧</value>
+<value>摨</value>
+<value>摩</value>
+<value>摰</value>
+<value>摱</value>
+<value>摲</value>
+<value>摳</value>
+<value>摴</value>
+<value>摵</value>
+<value>摶</value>
+<value>摷</value>
+<value>摸</value>
+<value>摹</value>
+<value>撀</value>
+<value>撁</value>
+<value>撂</value>
+<value>撃</value>
+<value>撄</value>
+<value>撅</value>
+<value>撆</value>
+<value>撇</value>
+<value>撈</value>
+<value>撉</value>
+<value>撐</value>
+<value>撑</value>
+<value>撒</value>
+<value>撓</value>
+<value>撔</value>
+<value>撕</value>
+<value>撖</value>
+<value>撗</value>
+<value>撘</value>
+<value>撙</value>
+<value>攀</value>
+<value>攁</value>
+<value>攂</value>
+<value>攃</value>
+<value>攄</value>
+<value>攅</value>
+<value>攆</value>
+<value>攇</value>
+<value>攈</value>
+<value>攉</value>
+<value>攐</value>
+<value>攑</value>
+<value>攒</value>
+<value>攓</value>
+<value>攔</value>
+<value>攕</value>
+<value>攖</value>
+<value>攗</value>
+<value>攘</value>
+<value>攙</value>
+<value>攠</value>
+<value>攡</value>
+<value>攢</value>
+<value>攣</value>
+<value>攤</value>
+<value>攥</value>
+<value>攦</value>
+<value>攧</value>
+<value>攨</value>
+<value>攩</value>
+<value>攰</value>
+<value>攱</value>
+<value>攲</value>
+<value>攳</value>
+<value>攴</value>
+<value>攵</value>
+<value>收</value>
+<value>攷</value>
+<value>攸</value>
+<value>改</value>
+<value>敀</value>
+<value>敁</value>
+<value>敂</value>
+<value>敃</value>
+<value>敄</value>
+<value>故</value>
+<value>敆</value>
+<value>敇</value>
+<value>效</value>
+<value>敉</value>
+<value>敐</value>
+<value>救</value>
+<value>敒</value>
+<value>敓</value>
+<value>敔</value>
+<value>敕</value>
+<value>敖</value>
+<value>敗</value>
+<value>敘</value>
+<value>教</value>
+<value>敠</value>
+<value>敡</value>
+<value>敢</value>
+<value>散</value>
+<value>敤</value>
+<value>敥</value>
+<value>敦</value>
+<value>敧</value>
+<value>敨</value>
+<value>敩</value>
+<value>数</value>
+<value>敱</value>
+<value>敲</value>
+<value>敳</value>
+<value>整</value>
+<value>敵</value>
+<value>敶</value>
+<value>敷</value>
+<value>數</value>
+<value>敹</value>
+<value>斀</value>
+<value>斁</value>
+<value>斂</value>
+<value>斃</value>
+<value>斄</value>
+<value>斅</value>
+<value>斆</value>
+<value>文</value>
+<value>斈</value>
+<value>斉</value>
+<value>斐</value>
+<value>斑</value>
+<value>斒</value>
+<value>斓</value>
+<value>斔</value>
+<value>斕</value>
+<value>斖</value>
+<value>斗</value>
+<value>斘</value>
+<value>料</value>
+<value>昀</value>
+<value>昁</value>
+<value>昂</value>
+<value>昃</value>
+<value>昄</value>
+<value>昅</value>
+<value>昆</value>
+<value>昇</value>
+<value>昈</value>
+<value>昉</value>
+<value>昐</value>
+<value>昑</value>
+<value>昒</value>
+<value>易</value>
+<value>昔</value>
+<value>昕</value>
+<value>昖</value>
+<value>昗</value>
+<value>昘</value>
+<value>昙</value>
+<value>映</value>
+<value>昡</value>
+<value>昢</value>
+<value>昣</value>
+<value>昤</value>
+<value>春</value>
+<value>昦</value>
+<value>昧</value>
+<value>昨</value>
+<value>昩</value>
+<value>昰</value>
+<value>昱</value>
+<value>昲</value>
+<value>昳</value>
+<value>昴</value>
+<value>昵</value>
+<value>昶</value>
+<value>昷</value>
+<value>昸</value>
+<value>昹</value>
+<value>晀</value>
+<value>晁</value>
+<value>時</value>
+<value>晃</value>
+<value>晄</value>
+<value>晅</value>
+<value>晆</value>
+<value>晇</value>
+<value>晈</value>
+<value>晉</value>
+<value>晐</value>
+<value>晑</value>
+<value>晒</value>
+<value>晓</value>
+<value>晔</value>
+<value>晕</value>
+<value>晖</value>
+<value>晗</value>
+<value>晘</value>
+<value>晙</value>
+<value>晠</value>
+<value>晡</value>
+<value>晢</value>
+<value>晣</value>
+<value>晤</value>
+<value>晥</value>
+<value>晦</value>
+<value>晧</value>
+<value>晨</value>
+<value>晩</value>
+<value>晰</value>
+<value>晱</value>
+<value>晲</value>
+<value>晳</value>
+<value>晴</value>
+<value>晵</value>
+<value>晶</value>
+<value>晷</value>
+<value>晸</value>
+<value>晹</value>
+<value>暀</value>
+<value>暁</value>
+<value>暂</value>
+<value>暃</value>
+<value>暄</value>
+<value>暅</value>
+<value>暆</value>
+<value>暇</value>
+<value>暈</value>
+<value>暉</value>
+<value>暐</value>
+<value>暑</value>
+<value>暒</value>
+<value>暓</value>
+<value>暔</value>
+<value>暕</value>
+<value>暖</value>
+<value>暗</value>
+<value>暘</value>
+<value>暙</value>
+<value>最</value>
+<value>朁</value>
+<value>朂</value>
+<value>會</value>
+<value>朄</value>
+<value>朅</value>
+<value>朆</value>
+<value>朇</value>
+<value>月</value>
+<value>有</value>
+<value>朐</value>
+<value>朑</value>
+<value>朒</value>
+<value>朓</value>
+<value>朔</value>
+<value>朕</value>
+<value>朖</value>
+<value>朗</value>
+<value>朘</value>
+<value>朙</value>
+<value>朠</value>
+<value>朡</value>
+<value>朢</value>
+<value>朣</value>
+<value>朤</value>
+<value>朥</value>
+<value>朦</value>
+<value>朧</value>
+<value>木</value>
+<value>朩</value>
+<value>朰</value>
+<value>朱</value>
+<value>朲</value>
+<value>朳</value>
+<value>朴</value>
+<value>朵</value>
+<value>朶</value>
+<value>朷</value>
+<value>朸</value>
+<value>朹</value>
+<value>杀</value>
+<value>杁</value>
+<value>杂</value>
+<value>权</value>
+<value>杄</value>
+<value>杅</value>
+<value>杆</value>
+<value>杇</value>
+<value>杈</value>
+<value>杉</value>
+<value>材</value>
+<value>村</value>
+<value>杒</value>
+<value>杓</value>
+<value>杔</value>
+<value>杕</value>
+<value>杖</value>
+<value>杗</value>
+<value>杘</value>
+<value>杙</value>
+<value>杠</value>
+<value>条</value>
+<value>杢</value>
+<value>杣</value>
+<value>杤</value>
+<value>来</value>
+<value>杦</value>
+<value>杧</value>
+<value>杨</value>
+<value>杩</value>
+<value>杰</value>
+<value>東</value>
+<value>杲</value>
+<value>杳</value>
+<value>杴</value>
+<value>杵</value>
+<value>杶</value>
+<value>杷</value>
+<value>杸</value>
+<value>杹</value>
+<value>枀</value>
+<value>极</value>
+<value>枂</value>
+<value>枃</value>
+<value>构</value>
+<value>枅</value>
+<value>枆</value>
+<value>枇</value>
+<value>枈</value>
+<value>枉</value>
+<value>析</value>
+<value>枑</value>
+<value>枒</value>
+<value>枓</value>
+<value>枔</value>
+<value>枕</value>
+<value>枖</value>
+<value>林</value>
+<value>枘</value>
+<value>枙</value>
+<value>栀</value>
+<value>栁</value>
+<value>栂</value>
+<value>栃</value>
+<value>栄</value>
+<value>栅</value>
+<value>栆</value>
+<value>标</value>
+<value>栈</value>
+<value>栉</value>
+<value>栐</value>
+<value>树</value>
+<value>栒</value>
+<value>栓</value>
+<value>栔</value>
+<value>栕</value>
+<value>栖</value>
+<value>栗</value>
+<value>栘</value>
+<value>栙</value>
+<value>栠</value>
+<value>校</value>
+<value>栢</value>
+<value>栣</value>
+<value>栤</value>
+<value>栥</value>
+<value>栦</value>
+<value>栧</value>
+<value>栨</value>
+<value>栩</value>
+<value>栰</value>
+<value>栱</value>
+<value>栲</value>
+<value>栳</value>
+<value>栴</value>
+<value>栵</value>
+<value>栶</value>
+<value>样</value>
+<value>核</value>
+<value>根</value>
+<value>桀</value>
+<value>桁</value>
+<value>桂</value>
+<value>桃</value>
+<value>桄</value>
+<value>桅</value>
+<value>框</value>
+<value>桇</value>
+<value>案</value>
+<value>桉</value>
+<value>桐</value>
+<value>桑</value>
+<value>桒</value>
+<value>桓</value>
+<value>桔</value>
+<value>桕</value>
+<value>桖</value>
+<value>桗</value>
+<value>桘</value>
+<value>桙</value>
+<value>桠</value>
+<value>桡</value>
+<value>桢</value>
+<value>档</value>
+<value>桤</value>
+<value>桥</value>
+<value>桦</value>
+<value>桧</value>
+<value>桨</value>
+<value>桩</value>
+<value>桰</value>
+<value>桱</value>
+<value>桲</value>
+<value>桳</value>
+<value>桴</value>
+<value>桵</value>
+<value>桶</value>
+<value>桷</value>
+<value>桸</value>
+<value>桹</value>
+<value>梀</value>
+<value>梁</value>
+<value>梂</value>
+<value>梃</value>
+<value>梄</value>
+<value>梅</value>
+<value>梆</value>
+<value>梇</value>
+<value>梈</value>
+<value>梉</value>
+<value>梐</value>
+<value>梑</value>
+<value>梒</value>
+<value>梓</value>
+<value>梔</value>
+<value>梕</value>
+<value>梖</value>
+<value>梗</value>
+<value>梘</value>
+<value>梙</value>
+<value>椀</value>
+<value>椁</value>
+<value>椂</value>
+<value>椃</value>
+<value>椄</value>
+<value>椅</value>
+<value>椆</value>
+<value>椇</value>
+<value>椈</value>
+<value>椉</value>
+<value>椐</value>
+<value>椑</value>
+<value>椒</value>
+<value>椓</value>
+<value>椔</value>
+<value>椕</value>
+<value>椖</value>
+<value>椗</value>
+<value>椘</value>
+<value>椙</value>
+<value>椠</value>
+<value>椡</value>
+<value>椢</value>
+<value>椣</value>
+<value>椤</value>
+<value>椥</value>
+<value>椦</value>
+<value>椧</value>
+<value>椨</value>
+<value>椩</value>
+<value>椰</value>
+<value>椱</value>
+<value>椲</value>
+<value>椳</value>
+<value>椴</value>
+<value>椵</value>
+<value>椶</value>
+<value>椷</value>
+<value>椸</value>
+<value>椹</value>
+<value>楀</value>
+<value>楁</value>
+<value>楂</value>
+<value>楃</value>
+<value>楄</value>
+<value>楅</value>
+<value>楆</value>
+<value>楇</value>
+<value>楈</value>
+<value>楉</value>
+<value>楐</value>
+<value>楑</value>
+<value>楒</value>
+<value>楓</value>
+<value>楔</value>
+<value>楕</value>
+<value>楖</value>
+<value>楗</value>
+<value>楘</value>
+<value>楙</value>
+<value>楠</value>
+<value>楡</value>
+<value>楢</value>
+<value>楣</value>
+<value>楤</value>
+<value>楥</value>
+<value>楦</value>
+<value>楧</value>
+<value>楨</value>
+<value>楩</value>
+<value>楰</value>
+<value>楱</value>
+<value>楲</value>
+<value>楳</value>
+<value>楴</value>
+<value>極</value>
+<value>楶</value>
+<value>楷</value>
+<value>楸</value>
+<value>楹</value>
+<value>榀</value>
+<value>榁</value>
+<value>概</value>
+<value>榃</value>
+<value>榄</value>
+<value>榅</value>
+<value>榆</value>
+<value>榇</value>
+<value>榈</value>
+<value>榉</value>
+<value>榐</value>
+<value>榑</value>
+<value>榒</value>
+<value>榓</value>
+<value>榔</value>
+<value>榕</value>
+<value>榖</value>
+<value>榗</value>
+<value>榘</value>
+<value>榙</value>
+<value>瀀</value>
+<value>瀁</value>
+<value>瀂</value>
+<value>瀃</value>
+<value>瀄</value>
+<value>瀅</value>
+<value>瀆</value>
+<value>瀇</value>
+<value>瀈</value>
+<value>瀉</value>
+<value>瀐</value>
+<value>瀑</value>
+<value>瀒</value>
+<value>瀓</value>
+<value>瀔</value>
+<value>瀕</value>
+<value>瀖</value>
+<value>瀗</value>
+<value>瀘</value>
+<value>瀙</value>
+<value>瀠</value>
+<value>瀡</value>
+<value>瀢</value>
+<value>瀣</value>
+<value>瀤</value>
+<value>瀥</value>
+<value>瀦</value>
+<value>瀧</value>
+<value>瀨</value>
+<value>瀩</value>
+<value>瀰</value>
+<value>瀱</value>
+<value>瀲</value>
+<value>瀳</value>
+<value>瀴</value>
+<value>瀵</value>
+<value>瀶</value>
+<value>瀷</value>
+<value>瀸</value>
+<value>瀹</value>
+<value>灀</value>
+<value>灁</value>
+<value>灂</value>
+<value>灃</value>
+<value>灄</value>
+<value>灅</value>
+<value>灆</value>
+<value>灇</value>
+<value>灈</value>
+<value>灉</value>
+<value>灐</value>
+<value>灑</value>
+<value>灒</value>
+<value>灓</value>
+<value>灔</value>
+<value>灕</value>
+<value>灖</value>
+<value>灗</value>
+<value>灘</value>
+<value>灙</value>
+<value>灠</value>
+<value>灡</value>
+<value>灢</value>
+<value>灣</value>
+<value>灤</value>
+<value>灥</value>
+<value>灦</value>
+<value>灧</value>
+<value>灨</value>
+<value>灩</value>
+<value>灰</value>
+<value>灱</value>
+<value>灲</value>
+<value>灳</value>
+<value>灴</value>
+<value>灵</value>
+<value>灶</value>
+<value>灷</value>
+<value>灸</value>
+<value>灹</value>
+<value>炀</value>
+<value>炁</value>
+<value>炂</value>
+<value>炃</value>
+<value>炄</value>
+<value>炅</value>
+<value>炆</value>
+<value>炇</value>
+<value>炈</value>
+<value>炉</value>
+<value>炐</value>
+<value>炑</value>
+<value>炒</value>
+<value>炓</value>
+<value>炔</value>
+<value>炕</value>
+<value>炖</value>
+<value>炗</value>
+<value>炘</value>
+<value>炙</value>
+<value>焀</value>
+<value>焁</value>
+<value>焂</value>
+<value>焃</value>
+<value>焄</value>
+<value>焅</value>
+<value>焆</value>
+<value>焇</value>
+<value>焈</value>
+<value>焉</value>
+<value>焐</value>
+<value>焑</value>
+<value>焒</value>
+<value>焓</value>
+<value>焔</value>
+<value>焕</value>
+<value>焖</value>
+<value>焗</value>
+<value>焘</value>
+<value>焙</value>
+<value>焠</value>
+<value>無</value>
+<value>焢</value>
+<value>焣</value>
+<value>焤</value>
+<value>焥</value>
+<value>焦</value>
+<value>焧</value>
+<value>焨</value>
+<value>焩</value>
+<value>焰</value>
+<value>焱</value>
+<value>焲</value>
+<value>焳</value>
+<value>焴</value>
+<value>焵</value>
+<value>然</value>
+<value>焷</value>
+<value>焸</value>
+<value>焹</value>
+<value>煀</value>
+<value>煁</value>
+<value>煂</value>
+<value>煃</value>
+<value>煄</value>
+<value>煅</value>
+<value>煆</value>
+<value>煇</value>
+<value>煈</value>
+<value>煉</value>
+<value>煐</value>
+<value>煑</value>
+<value>煒</value>
+<value>煓</value>
+<value>煔</value>
+<value>煕</value>
+<value>煖</value>
+<value>煗</value>
+<value>煘</value>
+<value>煙</value>
+<value>煠</value>
+<value>煡</value>
+<value>煢</value>
+<value>煣</value>
+<value>煤</value>
+<value>煥</value>
+<value>煦</value>
+<value>照</value>
+<value>煨</value>
+<value>煩</value>
+<value>煰</value>
+<value>煱</value>
+<value>煲</value>
+<value>煳</value>
+<value>煴</value>
+<value>煵</value>
+<value>煶</value>
+<value>煷</value>
+<value>煸</value>
+<value>煹</value>
+<value>熀</value>
+<value>熁</value>
+<value>熂</value>
+<value>熃</value>
+<value>熄</value>
+<value>熅</value>
+<value>熆</value>
+<value>熇</value>
+<value>熈</value>
+<value>熉</value>
+<value>熐</value>
+<value>熑</value>
+<value>熒</value>
+<value>熓</value>
+<value>熔</value>
+<value>熕</value>
+<value>熖</value>
+<value>熗</value>
+<value>熘</value>
+<value>熙</value>
+<value>爀</value>
+<value>爁</value>
+<value>爂</value>
+<value>爃</value>
+<value>爄</value>
+<value>爅</value>
+<value>爆</value>
+<value>爇</value>
+<value>爈</value>
+<value>爉</value>
+<value>爐</value>
+<value>爑</value>
+<value>爒</value>
+<value>爓</value>
+<value>爔</value>
+<value>爕</value>
+<value>爖</value>
+<value>爗</value>
+<value>爘</value>
+<value>爙</value>
+<value>爠</value>
+<value>爡</value>
+<value>爢</value>
+<value>爣</value>
+<value>爤</value>
+<value>爥</value>
+<value>爦</value>
+<value>爧</value>
+<value>爨</value>
+<value>爩</value>
+<value>爰</value>
+<value>爱</value>
+<value>爲</value>
+<value>爳</value>
+<value>爴</value>
+<value>爵</value>
+<value>父</value>
+<value>爷</value>
+<value>爸</value>
+<value>爹</value>
+<value>牀</value>
+<value>牁</value>
+<value>牂</value>
+<value>牃</value>
+<value>牄</value>
+<value>牅</value>
+<value>牆</value>
+<value>片</value>
+<value>版</value>
+<value>牉</value>
+<value>牐</value>
+<value>牑</value>
+<value>牒</value>
+<value>牓</value>
+<value>牔</value>
+<value>牕</value>
+<value>牖</value>
+<value>牗</value>
+<value>牘</value>
+<value>牙</value>
+<value>牠</value>
+<value>牡</value>
+<value>牢</value>
+<value>牣</value>
+<value>牤</value>
+<value>牥</value>
+<value>牦</value>
+<value>牧</value>
+<value>牨</value>
+<value>物</value>
+<value>牰</value>
+<value>牱</value>
+<value>牲</value>
+<value>牳</value>
+<value>牴</value>
+<value>牵</value>
+<value>牶</value>
+<value>牷</value>
+<value>牸</value>
+<value>特</value>
+<value>犀</value>
+<value>犁</value>
+<value>犂</value>
+<value>犃</value>
+<value>犄</value>
+<value>犅</value>
+<value>犆</value>
+<value>犇</value>
+<value>犈</value>
+<value>犉</value>
+<value>犐</value>
+<value>犑</value>
+<value>犒</value>
+<value>犓</value>
+<value>犔</value>
+<value>犕</value>
+<value>犖</value>
+<value>犗</value>
+<value>犘</value>
+<value>犙</value>
+<value>猀</value>
+<value>猁</value>
+<value>猂</value>
+<value>猃</value>
+<value>猄</value>
+<value>猅</value>
+<value>猆</value>
+<value>猇</value>
+<value>猈</value>
+<value>猉</value>
+<value>猐</value>
+<value>猑</value>
+<value>猒</value>
+<value>猓</value>
+<value>猔</value>
+<value>猕</value>
+<value>猖</value>
+<value>猗</value>
+<value>猘</value>
+<value>猙</value>
+<value>猠</value>
+<value>猡</value>
+<value>猢</value>
+<value>猣</value>
+<value>猤</value>
+<value>猥</value>
+<value>猦</value>
+<value>猧</value>
+<value>猨</value>
+<value>猩</value>
+<value>猰</value>
+<value>猱</value>
+<value>猲</value>
+<value>猳</value>
+<value>猴</value>
+<value>猵</value>
+<value>猶</value>
+<value>猷</value>
+<value>猸</value>
+<value>猹</value>
+<value>獀</value>
+<value>獁</value>
+<value>獂</value>
+<value>獃</value>
+<value>獄</value>
+<value>獅</value>
+<value>獆</value>
+<value>獇</value>
+<value>獈</value>
+<value>獉</value>
+<value>獐</value>
+<value>獑</value>
+<value>獒</value>
+<value>獓</value>
+<value>獔</value>
+<value>獕</value>
+<value>獖</value>
+<value>獗</value>
+<value>獘</value>
+<value>獙</value>
+<value>獠</value>
+<value>獡</value>
+<value>獢</value>
+<value>獣</value>
+<value>獤</value>
+<value>獥</value>
+<value>獦</value>
+<value>獧</value>
+<value>獨</value>
+<value>獩</value>
+<value>獰</value>
+<value>獱</value>
+<value>獲</value>
+<value>獳</value>
+<value>獴</value>
+<value>獵</value>
+<value>獶</value>
+<value>獷</value>
+<value>獸</value>
+<value>獹</value>
+<value>玀</value>
+<value>玁</value>
+<value>玂</value>
+<value>玃</value>
+<value>玄</value>
+<value>玅</value>
+<value>玆</value>
+<value>率</value>
+<value>玈</value>
+<value>玉</value>
+<value>玐</value>
+<value>玑</value>
+<value>玒</value>
+<value>玓</value>
+<value>玔</value>
+<value>玕</value>
+<value>玖</value>
+<value>玗</value>
+<value>玘</value>
+<value>玙</value>
+<value>琀</value>
+<value>琁</value>
+<value>琂</value>
+<value>球</value>
+<value>琄</value>
+<value>琅</value>
+<value>理</value>
+<value>琇</value>
+<value>琈</value>
+<value>琉</value>
+<value>琐</value>
+<value>琑</value>
+<value>琒</value>
+<value>琓</value>
+<value>琔</value>
+<value>琕</value>
+<value>琖</value>
+<value>琗</value>
+<value>琘</value>
+<value>琙</value>
+<value>琠</value>
+<value>琡</value>
+<value>琢</value>
+<value>琣</value>
+<value>琤</value>
+<value>琥</value>
+<value>琦</value>
+<value>琧</value>
+<value>琨</value>
+<value>琩</value>
+<value>琰</value>
+<value>琱</value>
+<value>琲</value>
+<value>琳</value>
+<value>琴</value>
+<value>琵</value>
+<value>琶</value>
+<value>琷</value>
+<value>琸</value>
+<value>琹</value>
+<value>瑀</value>
+<value>瑁</value>
+<value>瑂</value>
+<value>瑃</value>
+<value>瑄</value>
+<value>瑅</value>
+<value>瑆</value>
+<value>瑇</value>
+<value>瑈</value>
+<value>瑉</value>
+<value>瑐</value>
+<value>瑑</value>
+<value>瑒</value>
+<value>瑓</value>
+<value>瑔</value>
+<value>瑕</value>
+<value>瑖</value>
+<value>瑗</value>
+<value>瑘</value>
+<value>瑙</value>
+<value>瑠</value>
+<value>瑡</value>
+<value>瑢</value>
+<value>瑣</value>
+<value>瑤</value>
+<value>瑥</value>
+<value>瑦</value>
+<value>瑧</value>
+<value>瑨</value>
+<value>瑩</value>
+<value>瑰</value>
+<value>瑱</value>
+<value>瑲</value>
+<value>瑳</value>
+<value>瑴</value>
+<value>瑵</value>
+<value>瑶</value>
+<value>瑷</value>
+<value>瑸</value>
+<value>瑹</value>
+<value>璀</value>
+<value>璁</value>
+<value>璂</value>
+<value>璃</value>
+<value>璄</value>
+<value>璅</value>
+<value>璆</value>
+<value>璇</value>
+<value>璈</value>
+<value>璉</value>
+<value>璐</value>
+<value>璑</value>
+<value>璒</value>
+<value>璓</value>
+<value>璔</value>
+<value>璕</value>
+<value>璖</value>
+<value>璗</value>
+<value>璘</value>
+<value>璙</value>
+<value>甀</value>
+<value>甁</value>
+<value>甂</value>
+<value>甃</value>
+<value>甄</value>
+<value>甅</value>
+<value>甆</value>
+<value>甇</value>
+<value>甈</value>
+<value>甉</value>
+<value>甐</value>
+<value>甑</value>
+<value>甒</value>
+<value>甓</value>
+<value>甔</value>
+<value>甕</value>
+<value>甖</value>
+<value>甗</value>
+<value>甘</value>
+<value>甙</value>
+<value>甠</value>
+<value>甡</value>
+<value>產</value>
+<value>産</value>
+<value>甤</value>
+<value>甥</value>
+<value>甦</value>
+<value>甧</value>
+<value>用</value>
+<value>甩</value>
+<value>田</value>
+<value>由</value>
+<value>甲</value>
+<value>申</value>
+<value>甴</value>
+<value>电</value>
+<value>甶</value>
+<value>男</value>
+<value>甸</value>
+<value>甹</value>
+<value>畀</value>
+<value>畁</value>
+<value>畂</value>
+<value>畃</value>
+<value>畄</value>
+<value>畅</value>
+<value>畆</value>
+<value>畇</value>
+<value>畈</value>
+<value>畉</value>
+<value>畐</value>
+<value>畑</value>
+<value>畒</value>
+<value>畓</value>
+<value>畔</value>
+<value>畕</value>
+<value>畖</value>
+<value>畗</value>
+<value>畘</value>
+<value>留</value>
+<value>畠</value>
+<value>畡</value>
+<value>畢</value>
+<value>畣</value>
+<value>畤</value>
+<value>略</value>
+<value>畦</value>
+<value>畧</value>
+<value>畨</value>
+<value>畩</value>
+<value>異</value>
+<value>畱</value>
+<value>畲</value>
+<value>畳</value>
+<value>畴</value>
+<value>畵</value>
+<value>當</value>
+<value>畷</value>
+<value>畸</value>
+<value>畹</value>
+<value>疀</value>
+<value>疁</value>
+<value>疂</value>
+<value>疃</value>
+<value>疄</value>
+<value>疅</value>
+<value>疆</value>
+<value>疇</value>
+<value>疈</value>
+<value>疉</value>
+<value>疐</value>
+<value>疑</value>
+<value>疒</value>
+<value>疓</value>
+<value>疔</value>
+<value>疕</value>
+<value>疖</value>
+<value>疗</value>
+<value>疘</value>
+<value>疙</value>
+<value>瘀</value>
+<value>瘁</value>
+<value>瘂</value>
+<value>瘃</value>
+<value>瘄</value>
+<value>瘅</value>
+<value>瘆</value>
+<value>瘇</value>
+<value>瘈</value>
+<value>瘉</value>
+<value>瘐</value>
+<value>瘑</value>
+<value>瘒</value>
+<value>瘓</value>
+<value>瘔</value>
+<value>瘕</value>
+<value>瘖</value>
+<value>瘗</value>
+<value>瘘</value>
+<value>瘙</value>
+<value>瘠</value>
+<value>瘡</value>
+<value>瘢</value>
+<value>瘣</value>
+<value>瘤</value>
+<value>瘥</value>
+<value>瘦</value>
+<value>瘧</value>
+<value>瘨</value>
+<value>瘩</value>
+<value>瘰</value>
+<value>瘱</value>
+<value>瘲</value>
+<value>瘳</value>
+<value>瘴</value>
+<value>瘵</value>
+<value>瘶</value>
+<value>瘷</value>
+<value>瘸</value>
+<value>瘹</value>
+<value>癀</value>
+<value>癁</value>
+<value>療</value>
+<value>癃</value>
+<value>癄</value>
+<value>癅</value>
+<value>癆</value>
+<value>癇</value>
+<value>癈</value>
+<value>癉</value>
+<value>癐</value>
+<value>癑</value>
+<value>癒</value>
+<value>癓</value>
+<value>癔</value>
+<value>癕</value>
+<value>癖</value>
+<value>癗</value>
+<value>癘</value>
+<value>癙</value>
+<value>癠</value>
+<value>癡</value>
+<value>癢</value>
+<value>癣</value>
+<value>癤</value>
+<value>癥</value>
+<value>癦</value>
+<value>癧</value>
+<value>癨</value>
+<value>癩</value>
+<value>癰</value>
+<value>癱</value>
+<value>癲</value>
+<value>癳</value>
+<value>癴</value>
+<value>癵</value>
+<value>癶</value>
+<value>癷</value>
+<value>癸</value>
+<value>癹</value>
+<value>皀</value>
+<value>皁</value>
+<value>皂</value>
+<value>皃</value>
+<value>的</value>
+<value>皅</value>
+<value>皆</value>
+<value>皇</value>
+<value>皈</value>
+<value>皉</value>
+<value>皐</value>
+<value>皑</value>
+<value>皒</value>
+<value>皓</value>
+<value>皔</value>
+<value>皕</value>
+<value>皖</value>
+<value>皗</value>
+<value>皘</value>
+<value>皙</value>
+<value>眀</value>
+<value>省</value>
+<value>眂</value>
+<value>眃</value>
+<value>眄</value>
+<value>眅</value>
+<value>眆</value>
+<value>眇</value>
+<value>眈</value>
+<value>眉</value>
+<value>眐</value>
+<value>眑</value>
+<value>眒</value>
+<value>眓</value>
+<value>眔</value>
+<value>眕</value>
+<value>眖</value>
+<value>眗</value>
+<value>眘</value>
+<value>眙</value>
+<value>眠</value>
+<value>眡</value>
+<value>眢</value>
+<value>眣</value>
+<value>眤</value>
+<value>眥</value>
+<value>眦</value>
+<value>眧</value>
+<value>眨</value>
+<value>眩</value>
+<value>眰</value>
+<value>眱</value>
+<value>眲</value>
+<value>眳</value>
+<value>眴</value>
+<value>眵</value>
+<value>眶</value>
+<value>眷</value>
+<value>眸</value>
+<value>眹</value>
+<value>着</value>
+<value>睁</value>
+<value>睂</value>
+<value>睃</value>
+<value>睄</value>
+<value>睅</value>
+<value>睆</value>
+<value>睇</value>
+<value>睈</value>
+<value>睉</value>
+<value>睐</value>
+<value>睑</value>
+<value>睒</value>
+<value>睓</value>
+<value>睔</value>
+<value>睕</value>
+<value>睖</value>
+<value>睗</value>
+<value>睘</value>
+<value>睙</value>
+<value>睠</value>
+<value>睡</value>
+<value>睢</value>
+<value>督</value>
+<value>睤</value>
+<value>睥</value>
+<value>睦</value>
+<value>睧</value>
+<value>睨</value>
+<value>睩</value>
+<value>睰</value>
+<value>睱</value>
+<value>睲</value>
+<value>睳</value>
+<value>睴</value>
+<value>睵</value>
+<value>睶</value>
+<value>睷</value>
+<value>睸</value>
+<value>睹</value>
+<value>瞀</value>
+<value>瞁</value>
+<value>瞂</value>
+<value>瞃</value>
+<value>瞄</value>
+<value>瞅</value>
+<value>瞆</value>
+<value>瞇</value>
+<value>瞈</value>
+<value>瞉</value>
+<value>瞐</value>
+<value>瞑</value>
+<value>瞒</value>
+<value>瞓</value>
+<value>瞔</value>
+<value>瞕</value>
+<value>瞖</value>
+<value>瞗</value>
+<value>瞘</value>
+<value>瞙</value>
+<value>砀</value>
+<value>码</value>
+<value>砂</value>
+<value>砃</value>
+<value>砄</value>
+<value>砅</value>
+<value>砆</value>
+<value>砇</value>
+<value>砈</value>
+<value>砉</value>
+<value>砐</value>
+<value>砑</value>
+<value>砒</value>
+<value>砓</value>
+<value>研</value>
+<value>砕</value>
+<value>砖</value>
+<value>砗</value>
+<value>砘</value>
+<value>砙</value>
+<value>砠</value>
+<value>砡</value>
+<value>砢</value>
+<value>砣</value>
+<value>砤</value>
+<value>砥</value>
+<value>砦</value>
+<value>砧</value>
+<value>砨</value>
+<value>砩</value>
+<value>砰</value>
+<value>砱</value>
+<value>砲</value>
+<value>砳</value>
+<value>破</value>
+<value>砵</value>
+<value>砶</value>
+<value>砷</value>
+<value>砸</value>
+<value>砹</value>
+<value>础</value>
+<value>硁</value>
+<value>硂</value>
+<value>硃</value>
+<value>硄</value>
+<value>硅</value>
+<value>硆</value>
+<value>硇</value>
+<value>硈</value>
+<value>硉</value>
+<value>硐</value>
+<value>硑</value>
+<value>硒</value>
+<value>硓</value>
+<value>硔</value>
+<value>硕</value>
+<value>硖</value>
+<value>硗</value>
+<value>硘</value>
+<value>硙</value>
+<value>硠</value>
+<value>硡</value>
+<value>硢</value>
+<value>硣</value>
+<value>硤</value>
+<value>硥</value>
+<value>硦</value>
+<value>硧</value>
+<value>硨</value>
+<value>硩</value>
+<value>硰</value>
+<value>硱</value>
+<value>硲</value>
+<value>硳</value>
+<value>硴</value>
+<value>硵</value>
+<value>硶</value>
+<value>硷</value>
+<value>硸</value>
+<value>硹</value>
+<value>碀</value>
+<value>碁</value>
+<value>碂</value>
+<value>碃</value>
+<value>碄</value>
+<value>碅</value>
+<value>碆</value>
+<value>碇</value>
+<value>碈</value>
+<value>碉</value>
+<value>碐</value>
+<value>碑</value>
+<value>碒</value>
+<value>碓</value>
+<value>碔</value>
+<value>碕</value>
+<value>碖</value>
+<value>碗</value>
+<value>碘</value>
+<value>碙</value>
+<value>礀</value>
+<value>礁</value>
+<value>礂</value>
+<value>礃</value>
+<value>礄</value>
+<value>礅</value>
+<value>礆</value>
+<value>礇</value>
+<value>礈</value>
+<value>礉</value>
+<value>礐</value>
+<value>礑</value>
+<value>礒</value>
+<value>礓</value>
+<value>礔</value>
+<value>礕</value>
+<value>礖</value>
+<value>礗</value>
+<value>礘</value>
+<value>礙</value>
+<value>礠</value>
+<value>礡</value>
+<value>礢</value>
+<value>礣</value>
+<value>礤</value>
+<value>礥</value>
+<value>礦</value>
+<value>礧</value>
+<value>礨</value>
+<value>礩</value>
+<value>礰</value>
+<value>礱</value>
+<value>礲</value>
+<value>礳</value>
+<value>礴</value>
+<value>礵</value>
+<value>礶</value>
+<value>礷</value>
+<value>礸</value>
+<value>礹</value>
+<value>祀</value>
+<value>祁</value>
+<value>祂</value>
+<value>祃</value>
+<value>祄</value>
+<value>祅</value>
+<value>祆</value>
+<value>祇</value>
+<value>祈</value>
+<value>祉</value>
+<value>祐</value>
+<value>祑</value>
+<value>祒</value>
+<value>祓</value>
+<value>祔</value>
+<value>祕</value>
+<value>祖</value>
+<value>祗</value>
+<value>祘</value>
+<value>祙</value>
+<value>祠</value>
+<value>祡</value>
+<value>祢</value>
+<value>祣</value>
+<value>祤</value>
+<value>祥</value>
+<value>祦</value>
+<value>祧</value>
+<value>票</value>
+<value>祩</value>
+<value>祰</value>
+<value>祱</value>
+<value>祲</value>
+<value>祳</value>
+<value>祴</value>
+<value>祵</value>
+<value>祶</value>
+<value>祷</value>
+<value>祸</value>
+<value>祹</value>
+<value>禀</value>
+<value>禁</value>
+<value>禂</value>
+<value>禃</value>
+<value>禄</value>
+<value>禅</value>
+<value>禆</value>
+<value>禇</value>
+<value>禈</value>
+<value>禉</value>
+<value>禐</value>
+<value>禑</value>
+<value>禒</value>
+<value>禓</value>
+<value>禔</value>
+<value>禕</value>
+<value>禖</value>
+<value>禗</value>
+<value>禘</value>
+<value>禙</value>
+<value>耀</value>
+<value>老</value>
+<value>耂</value>
+<value>考</value>
+<value>耄</value>
+<value>者</value>
+<value>耆</value>
+<value>耇</value>
+<value>耈</value>
+<value>耉</value>
+<value>耐</value>
+<value>耑</value>
+<value>耒</value>
+<value>耓</value>
+<value>耔</value>
+<value>耕</value>
+<value>耖</value>
+<value>耗</value>
+<value>耘</value>
+<value>耙</value>
+<value>耠</value>
+<value>耡</value>
+<value>耢</value>
+<value>耣</value>
+<value>耤</value>
+<value>耥</value>
+<value>耦</value>
+<value>耧</value>
+<value>耨</value>
+<value>耩</value>
+<value>耰</value>
+<value>耱</value>
+<value>耲</value>
+<value>耳</value>
+<value>耴</value>
+<value>耵</value>
+<value>耶</value>
+<value>耷</value>
+<value>耸</value>
+<value>耹</value>
+<value>聀</value>
+<value>聁</value>
+<value>聂</value>
+<value>聃</value>
+<value>聄</value>
+<value>聅</value>
+<value>聆</value>
+<value>聇</value>
+<value>聈</value>
+<value>聉</value>
+<value>聐</value>
+<value>聑</value>
+<value>聒</value>
+<value>聓</value>
+<value>联</value>
+<value>聕</value>
+<value>聖</value>
+<value>聗</value>
+<value>聘</value>
+<value>聙</value>
+<value>聠</value>
+<value>聡</value>
+<value>聢</value>
+<value>聣</value>
+<value>聤</value>
+<value>聥</value>
+<value>聦</value>
+<value>聧</value>
+<value>聨</value>
+<value>聩</value>
+<value>聰</value>
+<value>聱</value>
+<value>聲</value>
+<value>聳</value>
+<value>聴</value>
+<value>聵</value>
+<value>聶</value>
+<value>職</value>
+<value>聸</value>
+<value>聹</value>
+<value>肀</value>
+<value>肁</value>
+<value>肂</value>
+<value>肃</value>
+<value>肄</value>
+<value>肅</value>
+<value>肆</value>
+<value>肇</value>
+<value>肈</value>
+<value>肉</value>
+<value>肐</value>
+<value>肑</value>
+<value>肒</value>
+<value>肓</value>
+<value>肔</value>
+<value>肕</value>
+<value>肖</value>
+<value>肗</value>
+<value>肘</value>
+<value>肙</value>
+<value>脀</value>
+<value>脁</value>
+<value>脂</value>
+<value>脃</value>
+<value>脄</value>
+<value>脅</value>
+<value>脆</value>
+<value>脇</value>
+<value>脈</value>
+<value>脉</value>
+<value>脐</value>
+<value>脑</value>
+<value>脒</value>
+<value>脓</value>
+<value>脔</value>
+<value>脕</value>
+<value>脖</value>
+<value>脗</value>
+<value>脘</value>
+<value>脙</value>
+<value>脠</value>
+<value>脡</value>
+<value>脢</value>
+<value>脣</value>
+<value>脤</value>
+<value>脥</value>
+<value>脦</value>
+<value>脧</value>
+<value>脨</value>
+<value>脩</value>
+<value>脰</value>
+<value>脱</value>
+<value>脲</value>
+<value>脳</value>
+<value>脴</value>
+<value>脵</value>
+<value>脶</value>
+<value>脷</value>
+<value>脸</value>
+<value>脹</value>
+<value>腀</value>
+<value>腁</value>
+<value>腂</value>
+<value>腃</value>
+<value>腄</value>
+<value>腅</value>
+<value>腆</value>
+<value>腇</value>
+<value>腈</value>
+<value>腉</value>
+<value>腐</value>
+<value>腑</value>
+<value>腒</value>
+<value>腓</value>
+<value>腔</value>
+<value>腕</value>
+<value>腖</value>
+<value>腗</value>
+<value>腘</value>
+<value>腙</value>
+<value>腠</value>
+<value>腡</value>
+<value>腢</value>
+<value>腣</value>
+<value>腤</value>
+<value>腥</value>
+<value>腦</value>
+<value>腧</value>
+<value>腨</value>
+<value>腩</value>
+<value>腰</value>
+<value>腱</value>
+<value>腲</value>
+<value>腳</value>
+<value>腴</value>
+<value>腵</value>
+<value>腶</value>
+<value>腷</value>
+<value>腸</value>
+<value>腹</value>
+<value>膀</value>
+<value>膁</value>
+<value>膂</value>
+<value>膃</value>
+<value>膄</value>
+<value>膅</value>
+<value>膆</value>
+<value>膇</value>
+<value>膈</value>
+<value>膉</value>
+<value>膐</value>
+<value>膑</value>
+<value>膒</value>
+<value>膓</value>
+<value>膔</value>
+<value>膕</value>
+<value>膖</value>
+<value>膗</value>
+<value>膘</value>
+<value>膙</value>
+<value>舀</value>
+<value>舁</value>
+<value>舂</value>
+<value>舃</value>
+<value>舄</value>
+<value>舅</value>
+<value>舆</value>
+<value>與</value>
+<value>興</value>
+<value>舉</value>
+<value>舐</value>
+<value>舑</value>
+<value>舒</value>
+<value>舓</value>
+<value>舔</value>
+<value>舕</value>
+<value>舖</value>
+<value>舗</value>
+<value>舘</value>
+<value>舙</value>
+<value>舠</value>
+<value>舡</value>
+<value>舢</value>
+<value>舣</value>
+<value>舤</value>
+<value>舥</value>
+<value>舦</value>
+<value>舧</value>
+<value>舨</value>
+<value>舩</value>
+<value>舰</value>
+<value>舱</value>
+<value>舲</value>
+<value>舳</value>
+<value>舴</value>
+<value>舵</value>
+<value>舶</value>
+<value>舷</value>
+<value>舸</value>
+<value>船</value>
+<value>艀</value>
+<value>艁</value>
+<value>艂</value>
+<value>艃</value>
+<value>艄</value>
+<value>艅</value>
+<value>艆</value>
+<value>艇</value>
+<value>艈</value>
+<value>艉</value>
+<value>艐</value>
+<value>艑</value>
+<value>艒</value>
+<value>艓</value>
+<value>艔</value>
+<value>艕</value>
+<value>艖</value>
+<value>艗</value>
+<value>艘</value>
+<value>艙</value>
+<value>艠</value>
+<value>艡</value>
+<value>艢</value>
+<value>艣</value>
+<value>艤</value>
+<value>艥</value>
+<value>艦</value>
+<value>艧</value>
+<value>艨</value>
+<value>艩</value>
+<value>艰</value>
+<value>艱</value>
+<value>色</value>
+<value>艳</value>
+<value>艴</value>
+<value>艵</value>
+<value>艶</value>
+<value>艷</value>
+<value>艸</value>
+<value>艹</value>
+<value>芀</value>
+<value>芁</value>
+<value>节</value>
+<value>芃</value>
+<value>芄</value>
+<value>芅</value>
+<value>芆</value>
+<value>芇</value>
+<value>芈</value>
+<value>芉</value>
+<value>芐</value>
+<value>芑</value>
+<value>芒</value>
+<value>芓</value>
+<value>芔</value>
+<value>芕</value>
+<value>芖</value>
+<value>芗</value>
+<value>芘</value>
+<value>芙</value>
+<value>茀</value>
+<value>茁</value>
+<value>茂</value>
+<value>范</value>
+<value>茄</value>
+<value>茅</value>
+<value>茆</value>
+<value>茇</value>
+<value>茈</value>
+<value>茉</value>
+<value>茐</value>
+<value>茑</value>
+<value>茒</value>
+<value>茓</value>
+<value>茔</value>
+<value>茕</value>
+<value>茖</value>
+<value>茗</value>
+<value>茘</value>
+<value>茙</value>
+<value>茠</value>
+<value>茡</value>
+<value>茢</value>
+<value>茣</value>
+<value>茤</value>
+<value>茥</value>
+<value>茦</value>
+<value>茧</value>
+<value>茨</value>
+<value>茩</value>
+<value>茰</value>
+<value>茱</value>
+<value>茲</value>
+<value>茳</value>
+<value>茴</value>
+<value>茵</value>
+<value>茶</value>
+<value>茷</value>
+<value>茸</value>
+<value>茹</value>
+<value>荀</value>
+<value>荁</value>
+<value>荂</value>
+<value>荃</value>
+<value>荄</value>
+<value>荅</value>
+<value>荆</value>
+<value>荇</value>
+<value>荈</value>
+<value>草</value>
+<value>荐</value>
+<value>荑</value>
+<value>荒</value>
+<value>荓</value>
+<value>荔</value>
+<value>荕</value>
+<value>荖</value>
+<value>荗</value>
+<value>荘</value>
+<value>荙</value>
+<value>荠</value>
+<value>荡</value>
+<value>荢</value>
+<value>荣</value>
+<value>荤</value>
+<value>荥</value>
+<value>荦</value>
+<value>荧</value>
+<value>荨</value>
+<value>荩</value>
+<value>荰</value>
+<value>荱</value>
+<value>荲</value>
+<value>荳</value>
+<value>荴</value>
+<value>荵</value>
+<value>荶</value>
+<value>荷</value>
+<value>荸</value>
+<value>荹</value>
+<value>莀</value>
+<value>莁</value>
+<value>莂</value>
+<value>莃</value>
+<value>莄</value>
+<value>莅</value>
+<value>莆</value>
+<value>莇</value>
+<value>莈</value>
+<value>莉</value>
+<value>莐</value>
+<value>莑</value>
+<value>莒</value>
+<value>莓</value>
+<value>莔</value>
+<value>莕</value>
+<value>莖</value>
+<value>莗</value>
+<value>莘</value>
+<value>莙</value>
+<value>萀</value>
+<value>萁</value>
+<value>萂</value>
+<value>萃</value>
+<value>萄</value>
+<value>萅</value>
+<value>萆</value>
+<value>萇</value>
+<value>萈</value>
+<value>萉</value>
+<value>萐</value>
+<value>萑</value>
+<value>萒</value>
+<value>萓</value>
+<value>萔</value>
+<value>萕</value>
+<value>萖</value>
+<value>萗</value>
+<value>萘</value>
+<value>萙</value>
+<value>萠</value>
+<value>萡</value>
+<value>萢</value>
+<value>萣</value>
+<value>萤</value>
+<value>营</value>
+<value>萦</value>
+<value>萧</value>
+<value>萨</value>
+<value>萩</value>
+<value>萰</value>
+<value>萱</value>
+<value>萲</value>
+<value>萳</value>
+<value>萴</value>
+<value>萵</value>
+<value>萶</value>
+<value>萷</value>
+<value>萸</value>
+<value>萹</value>
+<value>葀</value>
+<value>葁</value>
+<value>葂</value>
+<value>葃</value>
+<value>葄</value>
+<value>葅</value>
+<value>葆</value>
+<value>葇</value>
+<value>葈</value>
+<value>葉</value>
+<value>葐</value>
+<value>葑</value>
+<value>葒</value>
+<value>葓</value>
+<value>葔</value>
+<value>葕</value>
+<value>葖</value>
+<value>著</value>
+<value>葘</value>
+<value>葙</value>
+<value>葠</value>
+<value>葡</value>
+<value>葢</value>
+<value>董</value>
+<value>葤</value>
+<value>葥</value>
+<value>葦</value>
+<value>葧</value>
+<value>葨</value>
+<value>葩</value>
+<value>葰</value>
+<value>葱</value>
+<value>葲</value>
+<value>葳</value>
+<value>葴</value>
+<value>葵</value>
+<value>葶</value>
+<value>葷</value>
+<value>葸</value>
+<value>葹</value>
+<value>蒀</value>
+<value>蒁</value>
+<value>蒂</value>
+<value>蒃</value>
+<value>蒄</value>
+<value>蒅</value>
+<value>蒆</value>
+<value>蒇</value>
+<value>蒈</value>
+<value>蒉</value>
+<value>蒐</value>
+<value>蒑</value>
+<value>蒒</value>
+<value>蒓</value>
+<value>蒔</value>
+<value>蒕</value>
+<value>蒖</value>
+<value>蒗</value>
+<value>蒘</value>
+<value>蒙</value>
+<value>蔀</value>
+<value>蔁</value>
+<value>蔂</value>
+<value>蔃</value>
+<value>蔄</value>
+<value>蔅</value>
+<value>蔆</value>
+<value>蔇</value>
+<value>蔈</value>
+<value>蔉</value>
+<value>蔐</value>
+<value>蔑</value>
+<value>蔒</value>
+<value>蔓</value>
+<value>蔔</value>
+<value>蔕</value>
+<value>蔖</value>
+<value>蔗</value>
+<value>蔘</value>
+<value>蔙</value>
+<value>蔠</value>
+<value>蔡</value>
+<value>蔢</value>
+<value>蔣</value>
+<value>蔤</value>
+<value>蔥</value>
+<value>蔦</value>
+<value>蔧</value>
+<value>蔨</value>
+<value>蔩</value>
+<value>蔰</value>
+<value>蔱</value>
+<value>蔲</value>
+<value>蔳</value>
+<value>蔴</value>
+<value>蔵</value>
+<value>蔶</value>
+<value>蔷</value>
+<value>蔸</value>
+<value>蔹</value>
+<value>蕀</value>
+<value>蕁</value>
+<value>蕂</value>
+<value>蕃</value>
+<value>蕄</value>
+<value>蕅</value>
+<value>蕆</value>
+<value>蕇</value>
+<value>蕈</value>
+<value>蕉</value>
+<value>蕐</value>
+<value>蕑</value>
+<value>蕒</value>
+<value>蕓</value>
+<value>蕔</value>
+<value>蕕</value>
+<value>蕖</value>
+<value>蕗</value>
+<value>蕘</value>
+<value>蕙</value>
+<value>蕠</value>
+<value>蕡</value>
+<value>蕢</value>
+<value>蕣</value>
+<value>蕤</value>
+<value>蕥</value>
+<value>蕦</value>
+<value>蕧</value>
+<value>蕨</value>
+<value>蕩</value>
+<value>蕰</value>
+<value>蕱</value>
+<value>蕲</value>
+<value>蕳</value>
+<value>蕴</value>
+<value>蕵</value>
+<value>蕶</value>
+<value>蕷</value>
+<value>蕸</value>
+<value>蕹</value>
+<value>薀</value>
+<value>薁</value>
+<value>薂</value>
+<value>薃</value>
+<value>薄</value>
+<value>薅</value>
+<value>薆</value>
+<value>薇</value>
+<value>薈</value>
+<value>薉</value>
+<value>薐</value>
+<value>薑</value>
+<value>薒</value>
+<value>薓</value>
+<value>薔</value>
+<value>薕</value>
+<value>薖</value>
+<value>薗</value>
+<value>薘</value>
+<value>薙</value>
+<value>蘀</value>
+<value>蘁</value>
+<value>蘂</value>
+<value>蘃</value>
+<value>蘄</value>
+<value>蘅</value>
+<value>蘆</value>
+<value>蘇</value>
+<value>蘈</value>
+<value>蘉</value>
+<value>蘐</value>
+<value>蘑</value>
+<value>蘒</value>
+<value>蘓</value>
+<value>蘔</value>
+<value>蘕</value>
+<value>蘖</value>
+<value>蘗</value>
+<value>蘘</value>
+<value>蘙</value>
+<value>蘠</value>
+<value>蘡</value>
+<value>蘢</value>
+<value>蘣</value>
+<value>蘤</value>
+<value>蘥</value>
+<value>蘦</value>
+<value>蘧</value>
+<value>蘨</value>
+<value>蘩</value>
+<value>蘰</value>
+<value>蘱</value>
+<value>蘲</value>
+<value>蘳</value>
+<value>蘴</value>
+<value>蘵</value>
+<value>蘶</value>
+<value>蘷</value>
+<value>蘸</value>
+<value>蘹</value>
+<value>虀</value>
+<value>虁</value>
+<value>虂</value>
+<value>虃</value>
+<value>虄</value>
+<value>虅</value>
+<value>虆</value>
+<value>虇</value>
+<value>虈</value>
+<value>虉</value>
+<value>虐</value>
+<value>虑</value>
+<value>虒</value>
+<value>虓</value>
+<value>虔</value>
+<value>處</value>
+<value>虖</value>
+<value>虗</value>
+<value>虘</value>
+<value>虙</value>
+<value>虠</value>
+<value>虡</value>
+<value>虢</value>
+<value>虣</value>
+<value>虤</value>
+<value>虥</value>
+<value>虦</value>
+<value>虧</value>
+<value>虨</value>
+<value>虩</value>
+<value>虰</value>
+<value>虱</value>
+<value>虲</value>
+<value>虳</value>
+<value>虴</value>
+<value>虵</value>
+<value>虶</value>
+<value>虷</value>
+<value>虸</value>
+<value>虹</value>
+<value>蚀</value>
+<value>蚁</value>
+<value>蚂</value>
+<value>蚃</value>
+<value>蚄</value>
+<value>蚅</value>
+<value>蚆</value>
+<value>蚇</value>
+<value>蚈</value>
+<value>蚉</value>
+<value>蚐</value>
+<value>蚑</value>
+<value>蚒</value>
+<value>蚓</value>
+<value>蚔</value>
+<value>蚕</value>
+<value>蚖</value>
+<value>蚗</value>
+<value>蚘</value>
+<value>蚙</value>
+<value>蜀</value>
+<value>蜁</value>
+<value>蜂</value>
+<value>蜃</value>
+<value>蜄</value>
+<value>蜅</value>
+<value>蜆</value>
+<value>蜇</value>
+<value>蜈</value>
+<value>蜉</value>
+<value>蜐</value>
+<value>蜑</value>
+<value>蜒</value>
+<value>蜓</value>
+<value>蜔</value>
+<value>蜕</value>
+<value>蜖</value>
+<value>蜗</value>
+<value>蜘</value>
+<value>蜙</value>
+<value>蜠</value>
+<value>蜡</value>
+<value>蜢</value>
+<value>蜣</value>
+<value>蜤</value>
+<value>蜥</value>
+<value>蜦</value>
+<value>蜧</value>
+<value>蜨</value>
+<value>蜩</value>
+<value>蜰</value>
+<value>蜱</value>
+<value>蜲</value>
+<value>蜳</value>
+<value>蜴</value>
+<value>蜵</value>
+<value>蜶</value>
+<value>蜷</value>
+<value>蜸</value>
+<value>蜹</value>
+<value>蝀</value>
+<value>蝁</value>
+<value>蝂</value>
+<value>蝃</value>
+<value>蝄</value>
+<value>蝅</value>
+<value>蝆</value>
+<value>蝇</value>
+<value>蝈</value>
+<value>蝉</value>
+<value>蝐</value>
+<value>蝑</value>
+<value>蝒</value>
+<value>蝓</value>
+<value>蝔</value>
+<value>蝕</value>
+<value>蝖</value>
+<value>蝗</value>
+<value>蝘</value>
+<value>蝙</value>
+<value>蝠</value>
+<value>蝡</value>
+<value>蝢</value>
+<value>蝣</value>
+<value>蝤</value>
+<value>蝥</value>
+<value>蝦</value>
+<value>蝧</value>
+<value>蝨</value>
+<value>蝩</value>
+<value>蝰</value>
+<value>蝱</value>
+<value>蝲</value>
+<value>蝳</value>
+<value>蝴</value>
+<value>蝵</value>
+<value>蝶</value>
+<value>蝷</value>
+<value>蝸</value>
+<value>蝹</value>
+<value>螀</value>
+<value>螁</value>
+<value>螂</value>
+<value>螃</value>
+<value>螄</value>
+<value>螅</value>
+<value>螆</value>
+<value>螇</value>
+<value>螈</value>
+<value>螉</value>
+<value>螐</value>
+<value>螑</value>
+<value>螒</value>
+<value>螓</value>
+<value>螔</value>
+<value>螕</value>
+<value>螖</value>
+<value>螗</value>
+<value>螘</value>
+<value>螙</value>
+<value>蠀</value>
+<value>蠁</value>
+<value>蠂</value>
+<value>蠃</value>
+<value>蠄</value>
+<value>蠅</value>
+<value>蠆</value>
+<value>蠇</value>
+<value>蠈</value>
+<value>蠉</value>
+<value>蠐</value>
+<value>蠑</value>
+<value>蠒</value>
+<value>蠓</value>
+<value>蠔</value>
+<value>蠕</value>
+<value>蠖</value>
+<value>蠗</value>
+<value>蠘</value>
+<value>蠙</value>
+<value>蠠</value>
+<value>蠡</value>
+<value>蠢</value>
+<value>蠣</value>
+<value>蠤</value>
+<value>蠥</value>
+<value>蠦</value>
+<value>蠧</value>
+<value>蠨</value>
+<value>蠩</value>
+<value>蠰</value>
+<value>蠱</value>
+<value>蠲</value>
+<value>蠳</value>
+<value>蠴</value>
+<value>蠵</value>
+<value>蠶</value>
+<value>蠷</value>
+<value>蠸</value>
+<value>蠹</value>
+<value>血</value>
+<value>衁</value>
+<value>衂</value>
+<value>衃</value>
+<value>衄</value>
+<value>衅</value>
+<value>衆</value>
+<value>衇</value>
+<value>衈</value>
+<value>衉</value>
+<value>衐</value>
+<value>衑</value>
+<value>衒</value>
+<value>術</value>
+<value>衔</value>
+<value>衕</value>
+<value>衖</value>
+<value>街</value>
+<value>衘</value>
+<value>衙</value>
+<value>衠</value>
+<value>衡</value>
+<value>衢</value>
+<value>衣</value>
+<value>衤</value>
+<value>补</value>
+<value>衦</value>
+<value>衧</value>
+<value>表</value>
+<value>衩</value>
+<value>衰</value>
+<value>衱</value>
+<value>衲</value>
+<value>衳</value>
+<value>衴</value>
+<value>衵</value>
+<value>衶</value>
+<value>衷</value>
+<value>衸</value>
+<value>衹</value>
+<value>袀</value>
+<value>袁</value>
+<value>袂</value>
+<value>袃</value>
+<value>袄</value>
+<value>袅</value>
+<value>袆</value>
+<value>袇</value>
+<value>袈</value>
+<value>袉</value>
+<value>袐</value>
+<value>袑</value>
+<value>袒</value>
+<value>袓</value>
+<value>袔</value>
+<value>袕</value>
+<value>袖</value>
+<value>袗</value>
+<value>袘</value>
+<value>袙</value>
+<value>褀</value>
+<value>褁</value>
+<value>褂</value>
+<value>褃</value>
+<value>褄</value>
+<value>褅</value>
+<value>褆</value>
+<value>複</value>
+<value>褈</value>
+<value>褉</value>
+<value>褐</value>
+<value>褑</value>
+<value>褒</value>
+<value>褓</value>
+<value>褔</value>
+<value>褕</value>
+<value>褖</value>
+<value>褗</value>
+<value>褘</value>
+<value>褙</value>
+<value>褠</value>
+<value>褡</value>
+<value>褢</value>
+<value>褣</value>
+<value>褤</value>
+<value>褥</value>
+<value>褦</value>
+<value>褧</value>
+<value>褨</value>
+<value>褩</value>
+<value>褰</value>
+<value>褱</value>
+<value>褲</value>
+<value>褳</value>
+<value>褴</value>
+<value>褵</value>
+<value>褶</value>
+<value>褷</value>
+<value>褸</value>
+<value>褹</value>
+<value>襀</value>
+<value>襁</value>
+<value>襂</value>
+<value>襃</value>
+<value>襄</value>
+<value>襅</value>
+<value>襆</value>
+<value>襇</value>
+<value>襈</value>
+<value>襉</value>
+<value>襐</value>
+<value>襑</value>
+<value>襒</value>
+<value>襓</value>
+<value>襔</value>
+<value>襕</value>
+<value>襖</value>
+<value>襗</value>
+<value>襘</value>
+<value>襙</value>
+<value>襠</value>
+<value>襡</value>
+<value>襢</value>
+<value>襣</value>
+<value>襤</value>
+<value>襥</value>
+<value>襦</value>
+<value>襧</value>
+<value>襨</value>
+<value>襩</value>
+<value>襰</value>
+<value>襱</value>
+<value>襲</value>
+<value>襳</value>
+<value>襴</value>
+<value>襵</value>
+<value>襶</value>
+<value>襷</value>
+<value>襸</value>
+<value>襹</value>
+<value>覀</value>
+<value>要</value>
+<value>覂</value>
+<value>覃</value>
+<value>覄</value>
+<value>覅</value>
+<value>覆</value>
+<value>覇</value>
+<value>覈</value>
+<value>覉</value>
+<value>覐</value>
+<value>覑</value>
+<value>覒</value>
+<value>覓</value>
+<value>覔</value>
+<value>覕</value>
+<value>視</value>
+<value>覗</value>
+<value>覘</value>
+<value>覙</value>
+<value>退</value>
+<value>送</value>
+<value>适</value>
+<value>逃</value>
+<value>逄</value>
+<value>逅</value>
+<value>逆</value>
+<value>逇</value>
+<value>逈</value>
+<value>选</value>
+<value>逐</value>
+<value>逑</value>
+<value>递</value>
+<value>逓</value>
+<value>途</value>
+<value>逕</value>
+<value>逖</value>
+<value>逗</value>
+<value>逘</value>
+<value>這</value>
+<value>造</value>
+<value>逡</value>
+<value>逢</value>
+<value>連</value>
+<value>逤</value>
+<value>逥</value>
+<value>逦</value>
+<value>逧</value>
+<value>逨</value>
+<value>逩</value>
+<value>逰</value>
+<value>週</value>
+<value>進</value>
+<value>逳</value>
+<value>逴</value>
+<value>逵</value>
+<value>逶</value>
+<value>逷</value>
+<value>逸</value>
+<value>逹</value>
+<value>遀</value>
+<value>遁</value>
+<value>遂</value>
+<value>遃</value>
+<value>遄</value>
+<value>遅</value>
+<value>遆</value>
+<value>遇</value>
+<value>遈</value>
+<value>遉</value>
+<value>遐</value>
+<value>遑</value>
+<value>遒</value>
+<value>道</value>
+<value>達</value>
+<value>違</value>
+<value>遖</value>
+<value>遗</value>
+<value>遘</value>
+<value>遙</value>
+<value>遠</value>
+<value>遡</value>
+<value>遢</value>
+<value>遣</value>
+<value>遤</value>
+<value>遥</value>
+<value>遦</value>
+<value>遧</value>
+<value>遨</value>
+<value>適</value>
+<value>遰</value>
+<value>遱</value>
+<value>遲</value>
+<value>遳</value>
+<value>遴</value>
+<value>遵</value>
+<value>遶</value>
+<value>遷</value>
+<value>選</value>
+<value>遹</value>
+<value>邀</value>
+<value>邁</value>
+<value>邂</value>
+<value>邃</value>
+<value>還</value>
+<value>邅</value>
+<value>邆</value>
+<value>邇</value>
+<value>邈</value>
+<value>邉</value>
+<value>邐</value>
+<value>邑</value>
+<value>邒</value>
+<value>邓</value>
+<value>邔</value>
+<value>邕</value>
+<value>邖</value>
+<value>邗</value>
+<value>邘</value>
+<value>邙</value>
+<value>鄀</value>
+<value>鄁</value>
+<value>鄂</value>
+<value>鄃</value>
+<value>鄄</value>
+<value>鄅</value>
+<value>鄆</value>
+<value>鄇</value>
+<value>鄈</value>
+<value>鄉</value>
+<value>鄐</value>
+<value>鄑</value>
+<value>鄒</value>
+<value>鄓</value>
+<value>鄔</value>
+<value>鄕</value>
+<value>鄖</value>
+<value>鄗</value>
+<value>鄘</value>
+<value>鄙</value>
+<value>鄠</value>
+<value>鄡</value>
+<value>鄢</value>
+<value>鄣</value>
+<value>鄤</value>
+<value>鄥</value>
+<value>鄦</value>
+<value>鄧</value>
+<value>鄨</value>
+<value>鄩</value>
+<value>鄰</value>
+<value>鄱</value>
+<value>鄲</value>
+<value>鄳</value>
+<value>鄴</value>
+<value>鄵</value>
+<value>鄶</value>
+<value>鄷</value>
+<value>鄸</value>
+<value>鄹</value>
+<value>酀</value>
+<value>酁</value>
+<value>酂</value>
+<value>酃</value>
+<value>酄</value>
+<value>酅</value>
+<value>酆</value>
+<value>酇</value>
+<value>酈</value>
+<value>酉</value>
+<value>酐</value>
+<value>酑</value>
+<value>酒</value>
+<value>酓</value>
+<value>酔</value>
+<value>酕</value>
+<value>酖</value>
+<value>酗</value>
+<value>酘</value>
+<value>酙</value>
+<value>酠</value>
+<value>酡</value>
+<value>酢</value>
+<value>酣</value>
+<value>酤</value>
+<value>酥</value>
+<value>酦</value>
+<value>酧</value>
+<value>酨</value>
+<value>酩</value>
+<value>酰</value>
+<value>酱</value>
+<value>酲</value>
+<value>酳</value>
+<value>酴</value>
+<value>酵</value>
+<value>酶</value>
+<value>酷</value>
+<value>酸</value>
+<value>酹</value>
+<value>醀</value>
+<value>醁</value>
+<value>醂</value>
+<value>醃</value>
+<value>醄</value>
+<value>醅</value>
+<value>醆</value>
+<value>醇</value>
+<value>醈</value>
+<value>醉</value>
+<value>醐</value>
+<value>醑</value>
+<value>醒</value>
+<value>醓</value>
+<value>醔</value>
+<value>醕</value>
+<value>醖</value>
+<value>醗</value>
+<value>醘</value>
+<value>醙</value>
+<value>鈀</value>
+<value>鈁</value>
+<value>鈂</value>
+<value>鈃</value>
+<value>鈄</value>
+<value>鈅</value>
+<value>鈆</value>
+<value>鈇</value>
+<value>鈈</value>
+<value>鈉</value>
+<value>鈐</value>
+<value>鈑</value>
+<value>鈒</value>
+<value>鈓</value>
+<value>鈔</value>
+<value>鈕</value>
+<value>鈖</value>
+<value>鈗</value>
+<value>鈘</value>
+<value>鈙</value>
+<value>鈠</value>
+<value>鈡</value>
+<value>鈢</value>
+<value>鈣</value>
+<value>鈤</value>
+<value>鈥</value>
+<value>鈦</value>
+<value>鈧</value>
+<value>鈨</value>
+<value>鈩</value>
+<value>鈰</value>
+<value>鈱</value>
+<value>鈲</value>
+<value>鈳</value>
+<value>鈴</value>
+<value>鈵</value>
+<value>鈶</value>
+<value>鈷</value>
+<value>鈸</value>
+<value>鈹</value>
+<value>鉀</value>
+<value>鉁</value>
+<value>鉂</value>
+<value>鉃</value>
+<value>鉄</value>
+<value>鉅</value>
+<value>鉆</value>
+<value>鉇</value>
+<value>鉈</value>
+<value>鉉</value>
+<value>鉐</value>
+<value>鉑</value>
+<value>鉒</value>
+<value>鉓</value>
+<value>鉔</value>
+<value>鉕</value>
+<value>鉖</value>
+<value>鉗</value>
+<value>鉘</value>
+<value>鉙</value>
+<value>鉠</value>
+<value>鉡</value>
+<value>鉢</value>
+<value>鉣</value>
+<value>鉤</value>
+<value>鉥</value>
+<value>鉦</value>
+<value>鉧</value>
+<value>鉨</value>
+<value>鉩</value>
+<value>鉰</value>
+<value>鉱</value>
+<value>鉲</value>
+<value>鉳</value>
+<value>鉴</value>
+<value>鉵</value>
+<value>鉶</value>
+<value>鉷</value>
+<value>鉸</value>
+<value>鉹</value>
+<value>銀</value>
+<value>銁</value>
+<value>銂</value>
+<value>銃</value>
+<value>銄</value>
+<value>銅</value>
+<value>銆</value>
+<value>銇</value>
+<value>銈</value>
+<value>銉</value>
+<value>銐</value>
+<value>銑</value>
+<value>銒</value>
+<value>銓</value>
+<value>銔</value>
+<value>銕</value>
+<value>銖</value>
+<value>銗</value>
+<value>銘</value>
+<value>銙</value>
+<value>錀</value>
+<value>錁</value>
+<value>錂</value>
+<value>錃</value>
+<value>錄</value>
+<value>錅</value>
+<value>錆</value>
+<value>錇</value>
+<value>錈</value>
+<value>錉</value>
+<value>錐</value>
+<value>錑</value>
+<value>錒</value>
+<value>錓</value>
+<value>錔</value>
+<value>錕</value>
+<value>錖</value>
+<value>錗</value>
+<value>錘</value>
+<value>錙</value>
+<value>錠</value>
+<value>錡</value>
+<value>錢</value>
+<value>錣</value>
+<value>錤</value>
+<value>錥</value>
+<value>錦</value>
+<value>錧</value>
+<value>錨</value>
+<value>錩</value>
+<value>錰</value>
+<value>錱</value>
+<value>録</value>
+<value>錳</value>
+<value>錴</value>
+<value>錵</value>
+<value>錶</value>
+<value>錷</value>
+<value>錸</value>
+<value>錹</value>
+<value>鍀</value>
+<value>鍁</value>
+<value>鍂</value>
+<value>鍃</value>
+<value>鍄</value>
+<value>鍅</value>
+<value>鍆</value>
+<value>鍇</value>
+<value>鍈</value>
+<value>鍉</value>
+<value>鍐</value>
+<value>鍑</value>
+<value>鍒</value>
+<value>鍓</value>
+<value>鍔</value>
+<value>鍕</value>
+<value>鍖</value>
+<value>鍗</value>
+<value>鍘</value>
+<value>鍙</value>
+<value>鍠</value>
+<value>鍡</value>
+<value>鍢</value>
+<value>鍣</value>
+<value>鍤</value>
+<value>鍥</value>
+<value>鍦</value>
+<value>鍧</value>
+<value>鍨</value>
+<value>鍩</value>
+<value>鍰</value>
+<value>鍱</value>
+<value>鍲</value>
+<value>鍳</value>
+<value>鍴</value>
+<value>鍵</value>
+<value>鍶</value>
+<value>鍷</value>
+<value>鍸</value>
+<value>鍹</value>
+<value>鎀</value>
+<value>鎁</value>
+<value>鎂</value>
+<value>鎃</value>
+<value>鎄</value>
+<value>鎅</value>
+<value>鎆</value>
+<value>鎇</value>
+<value>鎈</value>
+<value>鎉</value>
+<value>鎐</value>
+<value>鎑</value>
+<value>鎒</value>
+<value>鎓</value>
+<value>鎔</value>
+<value>鎕</value>
+<value>鎖</value>
+<value>鎗</value>
+<value>鎘</value>
+<value>鎙</value>
+<value>鐀</value>
+<value>鐁</value>
+<value>鐂</value>
+<value>鐃</value>
+<value>鐄</value>
+<value>鐅</value>
+<value>鐆</value>
+<value>鐇</value>
+<value>鐈</value>
+<value>鐉</value>
+<value>鐐</value>
+<value>鐑</value>
+<value>鐒</value>
+<value>鐓</value>
+<value>鐔</value>
+<value>鐕</value>
+<value>鐖</value>
+<value>鐗</value>
+<value>鐘</value>
+<value>鐙</value>
+<value>鐠</value>
+<value>鐡</value>
+<value>鐢</value>
+<value>鐣</value>
+<value>鐤</value>
+<value>鐥</value>
+<value>鐦</value>
+<value>鐧</value>
+<value>鐨</value>
+<value>鐩</value>
+<value>鐰</value>
+<value>鐱</value>
+<value>鐲</value>
+<value>鐳</value>
+<value>鐴</value>
+<value>鐵</value>
+<value>鐶</value>
+<value>鐷</value>
+<value>鐸</value>
+<value>鐹</value>
+<value>鑀</value>
+<value>鑁</value>
+<value>鑂</value>
+<value>鑃</value>
+<value>鑄</value>
+<value>鑅</value>
+<value>鑆</value>
+<value>鑇</value>
+<value>鑈</value>
+<value>鑉</value>
+<value>鑐</value>
+<value>鑑</value>
+<value>鑒</value>
+<value>鑓</value>
+<value>鑔</value>
+<value>鑕</value>
+<value>鑖</value>
+<value>鑗</value>
+<value>鑘</value>
+<value>鑙</value>
+<value>鑠</value>
+<value>鑡</value>
+<value>鑢</value>
+<value>鑣</value>
+<value>鑤</value>
+<value>鑥</value>
+<value>鑦</value>
+<value>鑧</value>
+<value>鑨</value>
+<value>鑩</value>
+<value>鑰</value>
+<value>鑱</value>
+<value>鑲</value>
+<value>鑳</value>
+<value>鑴</value>
+<value>鑵</value>
+<value>鑶</value>
+<value>鑷</value>
+<value>鑸</value>
+<value>鑹</value>
+<value>钀</value>
+<value>钁</value>
+<value>钂</value>
+<value>钃</value>
+<value>钄</value>
+<value>钅</value>
+<value>钆</value>
+<value>钇</value>
+<value>针</value>
+<value>钉</value>
+<value>钐</value>
+<value>钑</value>
+<value>钒</value>
+<value>钓</value>
+<value>钔</value>
+<value>钕</value>
+<value>钖</value>
+<value>钗</value>
+<value>钘</value>
+<value>钙</value>
+<value>销</value>
+<value>锁</value>
+<value>锂</value>
+<value>锃</value>
+<value>锄</value>
+<value>锅</value>
+<value>锆</value>
+<value>锇</value>
+<value>锈</value>
+<value>锉</value>
+<value>锐</value>
+<value>锑</value>
+<value>锒</value>
+<value>锓</value>
+<value>锔</value>
+<value>锕</value>
+<value>锖</value>
+<value>锗</value>
+<value>锘</value>
+<value>错</value>
+<value>锠</value>
+<value>锡</value>
+<value>锢</value>
+<value>锣</value>
+<value>锤</value>
+<value>锥</value>
+<value>锦</value>
+<value>锧</value>
+<value>锨</value>
+<value>锩</value>
+<value>锰</value>
+<value>锱</value>
+<value>锲</value>
+<value>锳</value>
+<value>锴</value>
+<value>锵</value>
+<value>锶</value>
+<value>锷</value>
+<value>锸</value>
+<value>锹</value>
+<value>镀</value>
+<value>镁</value>
+<value>镂</value>
+<value>镃</value>
+<value>镄</value>
+<value>镅</value>
+<value>镆</value>
+<value>镇</value>
+<value>镈</value>
+<value>镉</value>
+<value>镐</value>
+<value>镑</value>
+<value>镒</value>
+<value>镓</value>
+<value>镔</value>
+<value>镕</value>
+<value>镖</value>
+<value>镗</value>
+<value>镘</value>
+<value>镙</value>
+<value>镠</value>
+<value>镡</value>
+<value>镢</value>
+<value>镣</value>
+<value>镤</value>
+<value>镥</value>
+<value>镦</value>
+<value>镧</value>
+<value>镨</value>
+<value>镩</value>
+<value>镰</value>
+<value>镱</value>
+<value>镲</value>
+<value>镳</value>
+<value>镴</value>
+<value>镵</value>
+<value>镶</value>
+<value>長</value>
+<value>镸</value>
+<value>镹</value>
+<value>門</value>
+<value>閁</value>
+<value>閂</value>
+<value>閃</value>
+<value>閄</value>
+<value>閅</value>
+<value>閆</value>
+<value>閇</value>
+<value>閈</value>
+<value>閉</value>
+<value>閐</value>
+<value>閑</value>
+<value>閒</value>
+<value>間</value>
+<value>閔</value>
+<value>閕</value>
+<value>閖</value>
+<value>閗</value>
+<value>閘</value>
+<value>閙</value>
+<value>阀</value>
+<value>阁</value>
+<value>阂</value>
+<value>阃</value>
+<value>阄</value>
+<value>阅</value>
+<value>阆</value>
+<value>阇</value>
+<value>阈</value>
+<value>阉</value>
+<value>阐</value>
+<value>阑</value>
+<value>阒</value>
+<value>阓</value>
+<value>阔</value>
+<value>阕</value>
+<value>阖</value>
+<value>阗</value>
+<value>阘</value>
+<value>阙</value>
+<value>阠</value>
+<value>阡</value>
+<value>阢</value>
+<value>阣</value>
+<value>阤</value>
+<value>阥</value>
+<value>阦</value>
+<value>阧</value>
+<value>阨</value>
+<value>阩</value>
+<value>阰</value>
+<value>阱</value>
+<value>防</value>
+<value>阳</value>
+<value>阴</value>
+<value>阵</value>
+<value>阶</value>
+<value>阷</value>
+<value>阸</value>
+<value>阹</value>
+<value>陀</value>
+<value>陁</value>
+<value>陂</value>
+<value>陃</value>
+<value>附</value>
+<value>际</value>
+<value>陆</value>
+<value>陇</value>
+<value>陈</value>
+<value>陉</value>
+<value>限</value>
+<value>陑</value>
+<value>陒</value>
+<value>陓</value>
+<value>陔</value>
+<value>陕</value>
+<value>陖</value>
+<value>陗</value>
+<value>陘</value>
+<value>陙</value>
+<value>陠</value>
+<value>陡</value>
+<value>院</value>
+<value>陣</value>
+<value>除</value>
+<value>陥</value>
+<value>陦</value>
+<value>陧</value>
+<value>陨</value>
+<value>险</value>
+<value>陰</value>
+<value>陱</value>
+<value>陲</value>
+<value>陳</value>
+<value>陴</value>
+<value>陵</value>
+<value>陶</value>
+<value>陷</value>
+<value>陸</value>
+<value>陹</value>
+<value>隀</value>
+<value>隁</value>
+<value>隂</value>
+<value>隃</value>
+<value>隄</value>
+<value>隅</value>
+<value>隆</value>
+<value>隇</value>
+<value>隈</value>
+<value>隉</value>
+<value>隐</value>
+<value>隑</value>
+<value>隒</value>
+<value>隓</value>
+<value>隔</value>
+<value>隕</value>
+<value>隖</value>
+<value>隗</value>
+<value>隘</value>
+<value>隙</value>
+<value>需</value>
+<value>霁</value>
+<value>霂</value>
+<value>霃</value>
+<value>霄</value>
+<value>霅</value>
+<value>霆</value>
+<value>震</value>
+<value>霈</value>
+<value>霉</value>
+<value>霐</value>
+<value>霑</value>
+<value>霒</value>
+<value>霓</value>
+<value>霔</value>
+<value>霕</value>
+<value>霖</value>
+<value>霗</value>
+<value>霘</value>
+<value>霙</value>
+<value>霠</value>
+<value>霡</value>
+<value>霢</value>
+<value>霣</value>
+<value>霤</value>
+<value>霥</value>
+<value>霦</value>
+<value>霧</value>
+<value>霨</value>
+<value>霩</value>
+<value>霰</value>
+<value>霱</value>
+<value>露</value>
+<value>霳</value>
+<value>霴</value>
+<value>霵</value>
+<value>霶</value>
+<value>霷</value>
+<value>霸</value>
+<value>霹</value>
+<value>靀</value>
+<value>靁</value>
+<value>靂</value>
+<value>靃</value>
+<value>靄</value>
+<value>靅</value>
+<value>靆</value>
+<value>靇</value>
+<value>靈</value>
+<value>靉</value>
+<value>靐</value>
+<value>靑</value>
+<value>青</value>
+<value>靓</value>
+<value>靔</value>
+<value>靕</value>
+<value>靖</value>
+<value>靗</value>
+<value>靘</value>
+<value>静</value>
+<value>靠</value>
+<value>靡</value>
+<value>面</value>
+<value>靣</value>
+<value>靤</value>
+<value>靥</value>
+<value>靦</value>
+<value>靧</value>
+<value>靨</value>
+<value>革</value>
+<value>靰</value>
+<value>靱</value>
+<value>靲</value>
+<value>靳</value>
+<value>靴</value>
+<value>靵</value>
+<value>靶</value>
+<value>靷</value>
+<value>靸</value>
+<value>靹</value>
+<value>鞀</value>
+<value>鞁</value>
+<value>鞂</value>
+<value>鞃</value>
+<value>鞄</value>
+<value>鞅</value>
+<value>鞆</value>
+<value>鞇</value>
+<value>鞈</value>
+<value>鞉</value>
+<value>鞐</value>
+<value>鞑</value>
+<value>鞒</value>
+<value>鞓</value>
+<value>鞔</value>
+<value>鞕</value>
+<value>鞖</value>
+<value>鞗</value>
+<value>鞘</value>
+<value>鞙</value>
+<value>頀</value>
+<value>頁</value>
+<value>頂</value>
+<value>頃</value>
+<value>頄</value>
+<value>項</value>
+<value>順</value>
+<value>頇</value>
+<value>須</value>
+<value>頉</value>
+<value>預</value>
+<value>頑</value>
+<value>頒</value>
+<value>頓</value>
+<value>頔</value>
+<value>頕</value>
+<value>頖</value>
+<value>頗</value>
+<value>領</value>
+<value>頙</value>
+<value>頠</value>
+<value>頡</value>
+<value>頢</value>
+<value>頣</value>
+<value>頤</value>
+<value>頥</value>
+<value>頦</value>
+<value>頧</value>
+<value>頨</value>
+<value>頩</value>
+<value>頰</value>
+<value>頱</value>
+<value>頲</value>
+<value>頳</value>
+<value>頴</value>
+<value>頵</value>
+<value>頶</value>
+<value>頷</value>
+<value>頸</value>
+<value>頹</value>
+<value>顀</value>
+<value>顁</value>
+<value>顂</value>
+<value>顃</value>
+<value>顄</value>
+<value>顅</value>
+<value>顆</value>
+<value>顇</value>
+<value>顈</value>
+<value>顉</value>
+<value>顐</value>
+<value>顑</value>
+<value>顒</value>
+<value>顓</value>
+<value>顔</value>
+<value>顕</value>
+<value>顖</value>
+<value>顗</value>
+<value>願</value>
+<value>顙</value>
+<value>顠</value>
+<value>顡</value>
+<value>顢</value>
+<value>顣</value>
+<value>顤</value>
+<value>顥</value>
+<value>顦</value>
+<value>顧</value>
+<value>顨</value>
+<value>顩</value>
+<value>顰</value>
+<value>顱</value>
+<value>顲</value>
+<value>顳</value>
+<value>顴</value>
+<value>页</value>
+<value>顶</value>
+<value>顷</value>
+<value>顸</value>
+<value>项</value>
+<value>颀</value>
+<value>颁</value>
+<value>颂</value>
+<value>颃</value>
+<value>预</value>
+<value>颅</value>
+<value>领</value>
+<value>颇</value>
+<value>颈</value>
+<value>颉</value>
+<value>颐</value>
+<value>频</value>
+<value>颒</value>
+<value>颓</value>
+<value>颔</value>
+<value>颕</value>
+<value>颖</value>
+<value>颗</value>
+<value>题</value>
+<value>颙</value>
+<value>餀</value>
+<value>餁</value>
+<value>餂</value>
+<value>餃</value>
+<value>餄</value>
+<value>餅</value>
+<value>餆</value>
+<value>餇</value>
+<value>餈</value>
+<value>餉</value>
+<value>餐</value>
+<value>餑</value>
+<value>餒</value>
+<value>餓</value>
+<value>餔</value>
+<value>餕</value>
+<value>餖</value>
+<value>餗</value>
+<value>餘</value>
+<value>餙</value>
+<value>餠</value>
+<value>餡</value>
+<value>餢</value>
+<value>餣</value>
+<value>餤</value>
+<value>餥</value>
+<value>餦</value>
+<value>餧</value>
+<value>館</value>
+<value>餩</value>
+<value>餰</value>
+<value>餱</value>
+<value>餲</value>
+<value>餳</value>
+<value>餴</value>
+<value>餵</value>
+<value>餶</value>
+<value>餷</value>
+<value>餸</value>
+<value>餹</value>
+<value>饀</value>
+<value>饁</value>
+<value>饂</value>
+<value>饃</value>
+<value>饄</value>
+<value>饅</value>
+<value>饆</value>
+<value>饇</value>
+<value>饈</value>
+<value>饉</value>
+<value>饐</value>
+<value>饑</value>
+<value>饒</value>
+<value>饓</value>
+<value>饔</value>
+<value>饕</value>
+<value>饖</value>
+<value>饗</value>
+<value>饘</value>
+<value>饙</value>
+<value>饠</value>
+<value>饡</value>
+<value>饢</value>
+<value>饣</value>
+<value>饤</value>
+<value>饥</value>
+<value>饦</value>
+<value>饧</value>
+<value>饨</value>
+<value>饩</value>
+<value>饰</value>
+<value>饱</value>
+<value>饲</value>
+<value>饳</value>
+<value>饴</value>
+<value>饵</value>
+<value>饶</value>
+<value>饷</value>
+<value>饸</value>
+<value>饹</value>
+<value>馀</value>
+<value>馁</value>
+<value>馂</value>
+<value>馃</value>
+<value>馄</value>
+<value>馅</value>
+<value>馆</value>
+<value>馇</value>
+<value>馈</value>
+<value>馉</value>
+<value>馐</value>
+<value>馑</value>
+<value>馒</value>
+<value>馓</value>
+<value>馔</value>
+<value>馕</value>
+<value>首</value>
+<value>馗</value>
+<value>馘</value>
+<value>香</value>
+</doc>
--- a/jaxws/.hgtags Fri Nov 20 15:40:23 2015 -0800
+++ b/jaxws/.hgtags Wed Jul 05 21:02:29 2017 +0200
@@ -338,3 +338,4 @@
b3e45213d574618f6520fa6978e4a14ba577c2db jdk9-b90
3b2a3cb658e41618bd152a7598d12e1f0c10e8f7 jdk9-b91
fe772cbc64f4e0418c5bf694e9e7123f02e1808f jdk9-b92
+5e94fbbb7032b3bba8254ddb1af8fc45a4d1448b jdk9-b93
--- a/jdk/.hgtags Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/.hgtags Wed Jul 05 21:02:29 2017 +0200
@@ -335,3 +335,4 @@
b433e4dfb830fea60e5187e4580791b62cc362d2 jdk9-b90
97624df5026a2fb191793697dbd2c604c4d5c66e jdk9-b91
6a5c99506f44538b879d8635a3979849ed587130 jdk9-b92
+2f12392d0dde768150c83087cdbdd0d33a4d866c jdk9-b93
--- a/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java Wed Jul 05 21:02:29 2017 +0200
@@ -1584,7 +1584,7 @@
* @param dstBegin the char index, not offset of byte[]
* @param coder the coder of dst[]
*/
- protected void getBytes(byte dst[], int dstBegin, byte coder) {
+ void getBytes(byte dst[], int dstBegin, byte coder) {
if (this.coder == coder) {
System.arraycopy(value, 0, dst, dstBegin << coder, count << coder);
} else { // this.coder == LATIN && coder == UTF16
@@ -1593,7 +1593,7 @@
}
/* for readObject() */
- protected void initBytes(char[] value, int off, int len) {
+ void initBytes(char[] value, int off, int len) {
if (String.COMPACT_STRINGS) {
this.value = StringUTF16.compress(value, off, len);
if (this.value != null) {
--- a/jdk/src/java.base/share/classes/java/lang/ProcessBuilder.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/ProcessBuilder.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,9 +26,11 @@
package java.lang;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.channels.Pipe;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
@@ -43,6 +45,11 @@
* {@link Process} instance with those attributes. The {@link
* #start()} method can be invoked repeatedly from the same instance
* to create new subprocesses with identical or related attributes.
+ * <p>
+ * The {@link #startPipeline startPipeline} method can be invoked to create
+ * a pipeline of new processes that send the output of each process
+ * directly to the next process. Each process has the attributes of
+ * its respective ProcessBuilder.
*
* <p>Each process builder manages these process attributes:
*
@@ -696,11 +703,37 @@
private Redirect() {}
}
+ /**
+ * Private implementation subclass of Redirect that holds a FileDescriptor for the
+ * output of a previously started Process.
+ * The FileDescriptor is used as the standard input of the next Process
+ * to be started.
+ */
+ static class RedirectPipeImpl extends Redirect {
+ final FileDescriptor fd;
+
+ RedirectPipeImpl() {
+ this.fd = new FileDescriptor();
+ }
+ @Override
+ public Type type() { return Type.PIPE; }
+
+ @Override
+ public String toString() { return type().toString();}
+
+ FileDescriptor getFd() { return fd; }
+ }
+
+ /**
+ * Return the array of redirects, creating the default as needed.
+ * @return the array of redirects
+ */
private Redirect[] redirects() {
- if (redirects == null)
+ if (redirects == null) {
redirects = new Redirect[] {
- Redirect.PIPE, Redirect.PIPE, Redirect.PIPE
+ Redirect.PIPE, Redirect.PIPE, Redirect.PIPE
};
+ }
return redirects;
}
@@ -1039,6 +1072,18 @@
* @see Runtime#exec(String[], String[], java.io.File)
*/
public Process start() throws IOException {
+ return start(redirects);
+ }
+
+ /**
+ * Start a new Process using an explicit array of redirects.
+ * See {@link #start} for details of starting each Process.
+ *
+ * @param redirect array of redirects for stdin, stdout, stderr
+ * @return the new Process
+ * @throws IOException if an I/O error occurs
+ */
+ private Process start(Redirect[] redirects) throws IOException {
// Must convert to array first -- a malicious user-supplied
// list might try to circumvent the security check.
String[] cmdarray = command.toArray(new String[command.size()]);
@@ -1089,4 +1134,171 @@
cause);
}
}
+
+ /**
+ * Starts a Process for each ProcessBuilder, creating a pipeline of
+ * processes linked by their standard output and standard input streams.
+ * The attributes of each ProcessBuilder are used to start the respective
+ * process except that as each process is started, its standard output
+ * is directed to the standard input of the next. The redirects for standard
+ * input of the first process and standard output of the last process are
+ * initialized using the redirect settings of the respective ProcessBuilder.
+ * All other {@code ProcessBuilder} redirects should be
+ * {@link Redirect#PIPE Redirect.PIPE}.
+ * <p>
+ * All input and output streams between the intermediate processes are
+ * not accessible.
+ * The {@link Process#getOutputStream standard input} of all processes
+ * except the first process are <i>null output streams</i>
+ * The {@link Process#getInputStream standard output} of all processes
+ * except the last process are <i>null input streams</i>.
+ * <p>
+ * The {@link #redirectErrorStream} of each ProcessBuilder applies to the
+ * respective process. If set to {@code true}, the error stream is written
+ * to the same stream as standard output.
+ * <p>
+ * If starting any of the processes throws an Exception, all processes
+ * are forcibly destroyed.
+ * <p>
+ * The {@code startPipeline} method performs the same checks on
+ * each ProcessBuilder as does the {@link #start} method. The new process
+ * will invoke the command and arguments given by {@link #command()},
+ * in a working directory as given by {@link #directory()},
+ * with a process environment as given by {@link #environment()}.
+ * <p>
+ * This method checks that the command is a valid operating
+ * system command. Which commands are valid is system-dependent,
+ * but at the very least the command must be a non-empty list of
+ * non-null strings.
+ * <p>
+ * A minimal set of system dependent environment variables may
+ * be required to start a process on some operating systems.
+ * As a result, the subprocess may inherit additional environment variable
+ * settings beyond those in the process builder's {@link #environment()}.
+ * <p>
+ * If there is a security manager, its
+ * {@link SecurityManager#checkExec checkExec}
+ * method is called with the first component of this object's
+ * {@code command} array as its argument. This may result in
+ * a {@link SecurityException} being thrown.
+ * <p>
+ * Starting an operating system process is highly system-dependent.
+ * Among the many things that can go wrong are:
+ * <ul>
+ * <li>The operating system program file was not found.
+ * <li>Access to the program file was denied.
+ * <li>The working directory does not exist.
+ * <li>Invalid character in command argument, such as NUL.
+ * </ul>
+ * <p>
+ * In such cases an exception will be thrown. The exact nature
+ * of the exception is system-dependent, but it will always be a
+ * subclass of {@link IOException}.
+ * <p>
+ * If the operating system does not support the creation of
+ * processes, an {@link UnsupportedOperationException} will be thrown.
+ * <p>
+ * Subsequent modifications to this process builder will not
+ * affect the returned {@link Process}.
+ * @apiNote
+ * For example to count the unique imports for all the files in a file hierarchy
+ * on a Unix compatible platform:
+ * <pre>{@code
+ * String directory = "/home/duke/src";
+ * ProcessBuilder[] builders = {
+ * new ProcessBuilder("find", directory, "-type", "f"),
+ new ProcessBuilder("xargs", "grep", "-h", "^import "),
+ new ProcessBuilder("awk", "{print $2;}"),
+ new ProcessBuilder("sort", "-u")};
+ * List<Process> processes = ProcessBuilder.startPipeline(
+ * Arrays.asList(builders));
+ * Process last = processes.get(processes.size()-1);
+ * try (InputStream is = last.getInputStream();
+ * Reader isr = new InputStreamReader(is);
+ * BufferedReader r = new BufferedReader(isr)) {
+ * long count = r.lines().count();
+ * }
+ * }</pre>
+ *
+ * @param builders a List of ProcessBuilders
+ * @return a {@code List<Process>}es started from the corresponding
+ * ProcessBuilder
+ * @throws IllegalArgumentException any of the redirects except the
+ * standard input of the first builder and the standard output of
+ * the last builder are not {@link Redirect#PIPE}.
+ * @throws NullPointerException
+ * if an element of the command list is null or
+ * if an element of the ProcessBuilder list is null or
+ * the builders argument is null
+ * @throws IndexOutOfBoundsException
+ * if the command is an empty list (has size {@code 0})
+ * @throws SecurityException
+ * if a security manager exists and
+ * <ul>
+ * <li>its
+ * {@link SecurityManager#checkExec checkExec}
+ * method doesn't allow creation of the subprocess, or
+ * <li>the standard input to the subprocess was
+ * {@linkplain #redirectInput redirected from a file}
+ * and the security manager's
+ * {@link SecurityManager#checkRead(String) checkRead} method
+ * denies read access to the file, or
+ * <li>the standard output or standard error of the
+ * subprocess was
+ * {@linkplain #redirectOutput redirected to a file}
+ * and the security manager's
+ * {@link SecurityManager#checkWrite(String) checkWrite} method
+ * denies write access to the file
+ * </ul>
+ *
+ * @throws UnsupportedOperationException
+ * If the operating system does not support the creation of processes
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ public static List<Process> startPipeline(List<ProcessBuilder> builders) throws IOException {
+ // Accumulate and check the builders
+ final int numBuilders = builders.size();
+ List<Process> processes = new ArrayList<>(numBuilders);
+ try {
+ Redirect prevOutput = null;
+ for (int index = 0; index < builders.size(); index++) {
+ ProcessBuilder builder = builders.get(index);
+ Redirect[] redirects = builder.redirects();
+ if (index > 0) {
+ // check the current Builder to see if it can take input from the previous
+ if (builder.redirectInput() != Redirect.PIPE) {
+ throw new IllegalArgumentException("builder redirectInput()" +
+ " must be PIPE except for the first builder: "
+ + builder.redirectInput());
+ }
+ redirects[0] = prevOutput;
+ }
+ if (index < numBuilders - 1) {
+ // check all but the last stage has output = PIPE
+ if (builder.redirectOutput() != Redirect.PIPE) {
+ throw new IllegalArgumentException("builder redirectOutput()" +
+ " must be PIPE except for the last builder: "
+ + builder.redirectOutput());
+ }
+ redirects[1] = new RedirectPipeImpl(); // placeholder for new output
+ }
+ processes.add(builder.start(redirects));
+ prevOutput = redirects[1];
+ }
+ } catch (Exception ex) {
+ // Cleanup processes already started
+ processes.forEach(Process::destroyForcibly);
+ processes.forEach(p -> {
+ try {
+ p.waitFor(); // Wait for it to exit
+ } catch (InterruptedException ie) {
+ // If interrupted; continue with next Process
+ Thread.currentThread().interrupt();
+ }
+ });
+ throw ex;
+ }
+ return processes;
+ }
}
--- a/jdk/src/java.base/share/classes/java/lang/RuntimePermission.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/RuntimePermission.java Wed Jul 05 21:02:29 2017 +0200
@@ -348,6 +348,19 @@
* {@code java.util.spi.LocaleServiceProvider}</a> for more
* information.</td>
* </tr>
+ *
+ * <tr>
+ * <td>loggerFinder</td>
+ * <td>This {@code RuntimePermission} is required to be granted to
+ * classes which subclass or call methods on
+ * {@code java.lang.System.LoggerFinder}. The permission is
+ * checked during invocation of the abstract base class constructor, as
+ * well as on the invocation of its public methods.
+ * This permission ensures trust in classes which provide loggers
+ * to system classes.</td>
+ * <td>See {@link java.lang.System.LoggerFinder java.lang.System.LoggerFinder}
+ * for more information.</td>
+ * </tr>
* </table>
*
* @implNote
--- a/jdk/src/java.base/share/classes/java/lang/System.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/System.java Wed Jul 05 21:02:29 2017 +0200
@@ -30,13 +30,14 @@
import java.security.AccessControlContext;
import java.util.Properties;
import java.util.PropertyPermission;
-import java.util.StringTokenizer;
import java.util.Map;
import java.security.AccessController;
import java.security.PrivilegedAction;
-import java.security.AllPermission;
import java.nio.channels.Channel;
import java.nio.channels.spi.SelectorProvider;
+import java.util.Objects;
+import java.util.ResourceBundle;
+import java.util.function.Supplier;
import sun.nio.ch.Interruptible;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
@@ -45,6 +46,9 @@
import jdk.internal.HotSpotIntrinsicCandidate;
import jdk.internal.misc.JavaLangAccess;;
import jdk.internal.misc.SharedSecrets;;
+import jdk.internal.logger.LoggerFinderLoader;
+import jdk.internal.logger.LazyLoggers;
+import jdk.internal.logger.LocalizedLoggerWrapper;
/**
* The <code>System</code> class contains several useful class fields
@@ -944,6 +948,648 @@
}
/**
+ * {@code System.Logger} instances log messages that will be
+ * routed to the underlying logging framework the {@link System.LoggerFinder
+ * LoggerFinder} uses.
+ * <p>
+ * {@code System.Logger} instances are typically obtained from
+ * the {@link java.lang.System System} class, by calling
+ * {@link java.lang.System#getLogger(java.lang.String) System.getLogger(loggerName)}
+ * or {@link java.lang.System#getLogger(java.lang.String, java.util.ResourceBundle)
+ * System.getLogger(loggerName, bundle)}.
+ *
+ * @see java.lang.System#getLogger(java.lang.String)
+ * @see java.lang.System#getLogger(java.lang.String, java.util.ResourceBundle)
+ * @see java.lang.System.LoggerFinder
+ *
+ * @since 9
+ *
+ */
+ public interface Logger {
+
+ /**
+ * System {@linkplain Logger loggers} levels.
+ * <p>
+ * A level has a {@linkplain #getName() name} and {@linkplain
+ * #getSeverity() severity}.
+ * Level values are {@link #ALL}, {@link #TRACE}, {@link #DEBUG},
+ * {@link #INFO}, {@link #WARNING}, {@link #ERROR}, {@link #OFF},
+ * by order of increasing severity.
+ * <br>
+ * {@link #ALL} and {@link #OFF}
+ * are simple markers with severities mapped respectively to
+ * {@link java.lang.Integer#MIN_VALUE Integer.MIN_VALUE} and
+ * {@link java.lang.Integer#MAX_VALUE Integer.MAX_VALUE}.
+ * <p>
+ * <b>Severity values and Mapping to {@code java.util.logging.Level}.</b>
+ * <p>
+ * {@linkplain System.Logger.Level System logger levels} are mapped to
+ * {@linkplain java.util.logging.Level java.util.logging levels}
+ * of corresponding severity.
+ * <br>The mapping is as follows:
+ * <br><br>
+ * <table border="1">
+ * <caption>System.Logger Severity Level Mapping</caption>
+ * <tr><td><b>System.Logger Levels</b></td>
+ * <td>{@link Logger.Level#ALL ALL}</td>
+ * <td>{@link Logger.Level#TRACE TRACE}</td>
+ * <td>{@link Logger.Level#DEBUG DEBUG}</td>
+ * <td>{@link Logger.Level#INFO INFO}</td>
+ * <td>{@link Logger.Level#WARNING WARNING}</td>
+ * <td>{@link Logger.Level#ERROR ERROR}</td>
+ * <td>{@link Logger.Level#OFF OFF}</td>
+ * </tr>
+ * <tr><td><b>java.util.logging Levels</b></td>
+ * <td>{@link java.util.logging.Level#ALL ALL}</td>
+ * <td>{@link java.util.logging.Level#FINER FINER}</td>
+ * <td>{@link java.util.logging.Level#FINE FINE}</td>
+ * <td>{@link java.util.logging.Level#INFO INFO}</td>
+ * <td>{@link java.util.logging.Level#WARNING WARNING}</td>
+ * <td>{@link java.util.logging.Level#SEVERE SEVERE}</td>
+ * <td>{@link java.util.logging.Level#OFF OFF}</td>
+ * </tr>
+ * </table>
+ *
+ * @since 9
+ *
+ * @see java.lang.System.LoggerFinder
+ * @see java.lang.System.Logger
+ */
+ public enum Level {
+
+ // for convenience, we're reusing java.util.logging.Level int values
+ // the mapping logic in sun.util.logging.PlatformLogger depends
+ // on this.
+ /**
+ * A marker to indicate that all levels are enabled.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@link Integer#MIN_VALUE}.
+ */
+ ALL(Integer.MIN_VALUE), // typically mapped to/from j.u.l.Level.ALL
+ /**
+ * {@code TRACE} level: usually used to log diagnostic information.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@code 400}.
+ */
+ TRACE(400), // typically mapped to/from j.u.l.Level.FINER
+ /**
+ * {@code DEBUG} level: usually used to log debug information traces.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@code 500}.
+ */
+ DEBUG(500), // typically mapped to/from j.u.l.Level.FINEST/FINE/CONFIG
+ /**
+ * {@code INFO} level: usually used to log information messages.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@code 800}.
+ */
+ INFO(800), // typically mapped to/from j.u.l.Level.INFO
+ /**
+ * {@code WARNING} level: usually used to log warning messages.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@code 900}.
+ */
+ WARNING(900), // typically mapped to/from j.u.l.Level.WARNING
+ /**
+ * {@code ERROR} level: usually used to log error messages.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@code 1000}.
+ */
+ ERROR(1000), // typically mapped to/from j.u.l.Level.SEVERE
+ /**
+ * A marker to indicate that all levels are disabled.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@link Integer#MAX_VALUE}.
+ */
+ OFF(Integer.MAX_VALUE); // typically mapped to/from j.u.l.Level.OFF
+
+ private final int severity;
+
+ private Level(int severity) {
+ this.severity = severity;
+ }
+
+ /**
+ * Returns the name of this level.
+ * @return this level {@linkplain #name()}.
+ */
+ public final String getName() {
+ return name();
+ }
+
+ /**
+ * Returns the severity of this level.
+ * A higher severity means a more severe condition.
+ * @return this level severity.
+ */
+ public final int getSeverity() {
+ return severity;
+ }
+ }
+
+ /**
+ * Returns the name of this logger.
+ *
+ * @return the logger name.
+ */
+ public String getName();
+
+ /**
+ * Checks if a message of the given level would be logged by
+ * this logger.
+ *
+ * @param level the log message level.
+ * @return {@code true} if the given log message level is currently
+ * being logged.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}.
+ */
+ public boolean isLoggable(Level level);
+
+ /**
+ * Logs a message.
+ *
+ * @implSpec The default implementation for this method calls
+ * {@code this.log(level, (ResourceBundle)null, msg, (Object[])null);}
+ *
+ * @param level the log message level.
+ * @param msg the string message (or a key in the message catalog, if
+ * this logger is a {@link
+ * LoggerFinder#getLocalizedLogger(java.lang.String, java.util.ResourceBundle, java.lang.Class)
+ * localized logger}); can be {@code null}.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}.
+ */
+ public default void log(Level level, String msg) {
+ log(level, (ResourceBundle) null, msg, (Object[]) null);
+ }
+
+ /**
+ * Logs a lazily supplied message.
+ * <p>
+ * If the logger is currently enabled for the given log message level
+ * then a message is logged that is the result produced by the
+ * given supplier function. Otherwise, the supplier is not operated on.
+ *
+ * @implSpec When logging is enabled for the given level, the default
+ * implementation for this method calls
+ * {@code this.log(level, (ResourceBundle)null, msgSupplier.get(), (Object[])null);}
+ *
+ * @param level the log message level.
+ * @param msgSupplier a supplier function that produces a message.
+ *
+ * @throws NullPointerException if {@code level} is {@code null},
+ * or {@code msgSupplier} is {@code null}.
+ */
+ public default void log(Level level, Supplier<String> msgSupplier) {
+ Objects.requireNonNull(msgSupplier);
+ if (isLoggable(Objects.requireNonNull(level))) {
+ log(level, (ResourceBundle) null, msgSupplier.get(), (Object[]) null);
+ }
+ }
+
+ /**
+ * Logs a message produced from the given object.
+ * <p>
+ * If the logger is currently enabled for the given log message level then
+ * a message is logged that, by default, is the result produced from
+ * calling toString on the given object.
+ * Otherwise, the object is not operated on.
+ *
+ * @implSpec When logging is enabled for the given level, the default
+ * implementation for this method calls
+ * {@code this.log(level, (ResourceBundle)null, obj.toString(), (Object[])null);}
+ *
+ * @param level the log message level.
+ * @param obj the object to log.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}, or
+ * {@code obj} is {@code null}.
+ */
+ public default void log(Level level, Object obj) {
+ Objects.requireNonNull(obj);
+ if (isLoggable(Objects.requireNonNull(level))) {
+ this.log(level, (ResourceBundle) null, obj.toString(), (Object[]) null);
+ }
+ }
+
+ /**
+ * Logs a message associated with a given throwable.
+ *
+ * @implSpec The default implementation for this method calls
+ * {@code this.log(level, (ResourceBundle)null, msg, thrown);}
+ *
+ * @param level the log message level.
+ * @param msg the string message (or a key in the message catalog, if
+ * this logger is a {@link
+ * LoggerFinder#getLocalizedLogger(java.lang.String, java.util.ResourceBundle, java.lang.Class)
+ * localized logger}); can be {@code null}.
+ * @param thrown a {@code Throwable} associated with the log message;
+ * can be {@code null}.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}.
+ */
+ public default void log(Level level, String msg, Throwable thrown) {
+ this.log(level, null, msg, thrown);
+ }
+
+ /**
+ * Logs a lazily supplied message associated with a given throwable.
+ * <p>
+ * If the logger is currently enabled for the given log message level
+ * then a message is logged that is the result produced by the
+ * given supplier function. Otherwise, the supplier is not operated on.
+ *
+ * @implSpec When logging is enabled for the given level, the default
+ * implementation for this method calls
+ * {@code this.log(level, (ResourceBundle)null, msgSupplier.get(), thrown);}
+ *
+ * @param level one of the log message level identifiers.
+ * @param msgSupplier a supplier function that produces a message.
+ * @param thrown a {@code Throwable} associated with log message;
+ * can be {@code null}.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}, or
+ * {@code msgSupplier} is {@code null}.
+ */
+ public default void log(Level level, Supplier<String> msgSupplier,
+ Throwable thrown) {
+ Objects.requireNonNull(msgSupplier);
+ if (isLoggable(Objects.requireNonNull(level))) {
+ this.log(level, null, msgSupplier.get(), thrown);
+ }
+ }
+
+ /**
+ * Logs a message with an optional list of parameters.
+ *
+ * @implSpec The default implementation for this method calls
+ * {@code this.log(level, (ResourceBundle)null, format, params);}
+ *
+ * @param level one of the log message level identifiers.
+ * @param format the string message format in {@link
+ * java.text.MessageFormat} format, (or a key in the message
+ * catalog, if this logger is a {@link
+ * LoggerFinder#getLocalizedLogger(java.lang.String, java.util.ResourceBundle, java.lang.Class)
+ * localized logger}); can be {@code null}.
+ * @param params an optional list of parameters to the message (may be
+ * none).
+ *
+ * @throws NullPointerException if {@code level} is {@code null}.
+ */
+ public default void log(Level level, String format, Object... params) {
+ this.log(level, null, format, params);
+ }
+
+ /**
+ * Logs a localized message associated with a given throwable.
+ * <p>
+ * If the given resource bundle is non-{@code null}, the {@code msg}
+ * string is localized using the given resource bundle.
+ * Otherwise the {@code msg} string is not localized.
+ *
+ * @param level the log message level.
+ * @param bundle a resource bundle to localize {@code msg}; can be
+ * {@code null}.
+ * @param msg the string message (or a key in the message catalog,
+ * if {@code bundle} is not {@code null}); can be {@code null}.
+ * @param thrown a {@code Throwable} associated with the log message;
+ * can be {@code null}.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}.
+ */
+ public void log(Level level, ResourceBundle bundle, String msg,
+ Throwable thrown);
+
+ /**
+ * Logs a message with resource bundle and an optional list of
+ * parameters.
+ * <p>
+ * If the given resource bundle is non-{@code null}, the {@code format}
+ * string is localized using the given resource bundle.
+ * Otherwise the {@code format} string is not localized.
+ *
+ * @param level the log message level.
+ * @param bundle a resource bundle to localize {@code format}; can be
+ * {@code null}.
+ * @param format the string message format in {@link
+ * java.text.MessageFormat} format, (or a key in the message
+ * catalog if {@code bundle} is not {@code null}); can be {@code null}.
+ * @param params an optional list of parameters to the message (may be
+ * none).
+ *
+ * @throws NullPointerException if {@code level} is {@code null}.
+ */
+ public void log(Level level, ResourceBundle bundle, String format,
+ Object... params);
+
+
+ }
+
+ /**
+ * The {@code LoggerFinder} service is responsible for creating, managing,
+ * and configuring loggers to the underlying framework it uses.
+ * <p>
+ * A logger finder is a concrete implementation of this class that has a
+ * zero-argument constructor and implements the abstract methods defined
+ * by this class.
+ * The loggers returned from a logger finder are capable of routing log
+ * messages to the logging backend this provider supports.
+ * A given invocation of the Java Runtime maintains a single
+ * system-wide LoggerFinder instance that is loaded as follows:
+ * <ul>
+ * <li>First it finds any custom {@code LoggerFinder} provider
+ * using the {@link java.util.ServiceLoader} facility with the
+ * {@linkplain ClassLoader#getSystemClassLoader() system class
+ * loader}.</li>
+ * <li>If no {@code LoggerFinder} provider is found, the system default
+ * {@code LoggerFinder} implementation will be used.</li>
+ * </ul>
+ * <p>
+ * An application can replace the logging backend
+ * <i>even when the java.logging module is present</i>, by simply providing
+ * and declaring an implementation of the {@link LoggerFinder} service.
+ * <p>
+ * <b>Default Implementation</b>
+ * <p>
+ * The system default {@code LoggerFinder} implementation uses
+ * {@code java.util.logging} as the backend framework when the
+ * {@code java.logging} module is present.
+ * It returns a {@linkplain System.Logger logger} instance
+ * that will route log messages to a {@link java.util.logging.Logger
+ * java.util.logging.Logger}. Otherwise, if {@code java.logging} is not
+ * present, the default implementation will return a simple logger
+ * instance that will route log messages of {@code INFO} level and above to
+ * the console ({@code System.err}).
+ * <p>
+ * <b>Logging Configuration</b>
+ * <p>
+ * {@linkplain Logger Logger} instances obtained from the
+ * {@code LoggerFinder} factory methods are not directly configurable by
+ * the application. Configuration is the responsibility of the underlying
+ * logging backend, and usually requires using APIs specific to that backend.
+ * <p>For the default {@code LoggerFinder} implementation
+ * using {@code java.util.logging} as its backend, refer to
+ * {@link java.util.logging java.util.logging} for logging configuration.
+ * For the default {@code LoggerFinder} implementation returning simple loggers
+ * when the {@code java.logging} module is absent, the configuration
+ * is implementation dependent.
+ * <p>
+ * Usually an application that uses a logging framework will log messages
+ * through a logger facade defined (or supported) by that framework.
+ * Applications that wish to use an external framework should log
+ * through the facade associated with that framework.
+ * <p>
+ * A system class that needs to log messages will typically obtain
+ * a {@link System.Logger} instance to route messages to the logging
+ * framework selected by the application.
+ * <p>
+ * Libraries and classes that only need loggers to produce log messages
+ * should not attempt to configure loggers by themselves, as that
+ * would make them dependent from a specific implementation of the
+ * {@code LoggerFinder} service.
+ * <p>
+ * In addition, when a security manager is present, loggers provided to
+ * system classes should not be directly configurable through the logging
+ * backend without requiring permissions.
+ * <br>
+ * It is the responsibility of the provider of
+ * the concrete {@code LoggerFinder} implementation to ensure that
+ * these loggers are not configured by untrusted code without proper
+ * permission checks, as configuration performed on such loggers usually
+ * affects all applications in the same Java Runtime.
+ * <p>
+ * <b>Message Levels and Mapping to backend levels</b>
+ * <p>
+ * A logger finder is responsible for mapping from a {@code
+ * System.Logger.Level} to a level supported by the logging backend it uses.
+ * <br>The default LoggerFinder using {@code java.util.logging} as the backend
+ * maps {@code System.Logger} levels to
+ * {@linkplain java.util.logging.Level java.util.logging} levels
+ * of corresponding severity - as described in {@link Logger.Level
+ * Logger.Level}.
+ *
+ * @see java.lang.System
+ * @see java.lang.System.Logger
+ *
+ * @since 9
+ */
+ public static abstract class LoggerFinder {
+ /**
+ * The {@code RuntimePermission("loggerFinder")} is
+ * necessary to subclass and instantiate the {@code LoggerFinder} class,
+ * as well as to obtain loggers from an instance of that class.
+ */
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+
+ /**
+ * Creates a new instance of {@code LoggerFinder}.
+ *
+ * @implNote It is recommended that a {@code LoggerFinder} service
+ * implementation does not perform any heavy initialization in its
+ * constructor, in order to avoid possible risks of deadlock or class
+ * loading cycles during the instantiation of the service provider.
+ *
+ * @throws SecurityException if a security manager is present and its
+ * {@code checkPermission} method doesn't allow the
+ * {@code RuntimePermission("loggerFinder")}.
+ */
+ protected LoggerFinder() {
+ this(checkPermission());
+ }
+
+ private LoggerFinder(Void unused) {
+ // nothing to do.
+ }
+
+ private static Void checkPermission() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGERFINDER_PERMISSION);
+ }
+ return null;
+ }
+
+ /**
+ * Returns an instance of {@link Logger Logger}
+ * for the given {@code caller}.
+ *
+ * @param name the name of the logger.
+ * @param caller the class for which the logger is being requested;
+ * can be {@code null}.
+ *
+ * @return a {@link Logger logger} suitable for the given caller's
+ * use.
+ * @throws NullPointerException if {@code name} is {@code null} or
+ * {@code caller} is {@code null}.
+ * @throws SecurityException if a security manager is present and its
+ * {@code checkPermission} method doesn't allow the
+ * {@code RuntimePermission("loggerFinder")}.
+ */
+ public abstract Logger getLogger(String name, /* Module */ Class<?> caller);
+
+ /**
+ * Returns a localizable instance of {@link Logger Logger}
+ * for the given {@code caller}.
+ * The returned logger will use the provided resource bundle for
+ * message localization.
+ *
+ * @implSpec By default, this method calls {@link
+ * #getLogger(java.lang.String, java.lang.Class)
+ * this.getLogger(name, caller)} to obtain a logger, then wraps that
+ * logger in a {@link Logger} instance where all methods that do not
+ * take a {@link ResourceBundle} as parameter are redirected to one
+ * which does - passing the given {@code bundle} for
+ * localization. So for instance, a call to {@link
+ * Logger#log(Level, String) Logger.log(Level.INFO, msg)}
+ * will end up as a call to {@link
+ * Logger#log(Level, ResourceBundle, String, Object...)
+ * Logger.log(Level.INFO, bundle, msg, (Object[])null)} on the wrapped
+ * logger instance.
+ * Note however that by default, string messages returned by {@link
+ * java.util.function.Supplier Supplier<String>} will not be
+ * localized, as it is assumed that such strings are messages which are
+ * already constructed, rather than keys in a resource bundle.
+ * <p>
+ * An implementation of {@code LoggerFinder} may override this method,
+ * for example, when the underlying logging backend provides its own
+ * mechanism for localizing log messages, then such a
+ * {@code LoggerFinder} would be free to return a logger
+ * that makes direct use of the mechanism provided by the backend.
+ *
+ * @param name the name of the logger.
+ * @param bundle a resource bundle; can be {@code null}.
+ * @param caller the class for which the logger is being requested.
+ * @return an instance of {@link Logger Logger} which will use the
+ * provided resource bundle for message localization.
+ *
+ * @throws NullPointerException if {@code name} is {@code null} or
+ * {@code caller} is {@code null}.
+ * @throws SecurityException if a security manager is present and its
+ * {@code checkPermission} method doesn't allow the
+ * {@code RuntimePermission("loggerFinder")}.
+ */
+ public Logger getLocalizedLogger(String name, ResourceBundle bundle,
+ /* Module */ Class<?> caller) {
+ return new LocalizedLoggerWrapper<>(getLogger(name, caller), bundle);
+ }
+
+ /**
+ * Returns the {@code LoggerFinder} instance. There is one
+ * single system-wide {@code LoggerFinder} instance in
+ * the Java Runtime. See the class specification of how the
+ * {@link LoggerFinder LoggerFinder} implementation is located and
+ * loaded.
+
+ * @return the {@link LoggerFinder LoggerFinder} instance.
+ * @throws SecurityException if a security manager is present and its
+ * {@code checkPermission} method doesn't allow the
+ * {@code RuntimePermission("loggerFinder")}.
+ */
+ public static LoggerFinder getLoggerFinder() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGERFINDER_PERMISSION);
+ }
+ return accessProvider();
+ }
+
+
+ private static volatile LoggerFinder service;
+ static LoggerFinder accessProvider() {
+ // We do not need to synchronize: LoggerFinderLoader will
+ // always return the same instance, so if we don't have it,
+ // just fetch it again.
+ if (service == null) {
+ PrivilegedAction<LoggerFinder> pa =
+ () -> LoggerFinderLoader.getLoggerFinder();
+ service = AccessController.doPrivileged(pa, null,
+ LOGGERFINDER_PERMISSION);
+ }
+ return service;
+ }
+
+ }
+
+
+ /**
+ * Returns an instance of {@link Logger Logger} for the caller's
+ * use.
+ *
+ * @implSpec
+ * Instances returned by this method route messages to loggers
+ * obtained by calling {@link LoggerFinder#getLogger(java.lang.String, java.lang.Class)
+ * LoggerFinder.getLogger(name, caller)}.
+ *
+ * @apiNote
+ * This method may defer calling the {@link
+ * LoggerFinder#getLogger(java.lang.String, java.lang.Class)
+ * LoggerFinder.getLogger} method to create an actual logger supplied by
+ * the logging backend, for instance, to allow loggers to be obtained during
+ * the system initialization time.
+ *
+ * @param name the name of the logger.
+ * @return an instance of {@link Logger} that can be used by the calling
+ * class.
+ * @throws NullPointerException if {@code name} is {@code null}.
+ */
+ @CallerSensitive
+ public static Logger getLogger(String name) {
+ Objects.requireNonNull(name);
+ final Class<?> caller = Reflection.getCallerClass();
+ return LazyLoggers.getLogger(name, caller);
+ }
+
+ /**
+ * Returns a localizable instance of {@link Logger
+ * Logger} for the caller's use.
+ * The returned logger will use the provided resource bundle for message
+ * localization.
+ *
+ * @implSpec
+ * The returned logger will perform message localization as specified
+ * by {@link LoggerFinder#getLocalizedLogger(java.lang.String,
+ * java.util.ResourceBundle, java.lang.Class)
+ * LoggerFinder.getLocalizedLogger(name, bundle, caller}.
+ *
+ * @apiNote
+ * This method is intended to be used after the system is fully initialized.
+ * This method may trigger the immediate loading and initialization
+ * of the {@link LoggerFinder} service, which may cause issues if the
+ * Java Runtime is not ready to initialize the concrete service
+ * implementation yet.
+ * System classes which may be loaded early in the boot sequence and
+ * need to log localized messages should create a logger using
+ * {@link #getLogger(java.lang.String)} and then use the log methods that
+ * take a resource bundle as parameter.
+ *
+ * @param name the name of the logger.
+ * @param bundle a resource bundle.
+ * @return an instance of {@link Logger} which will use the provided
+ * resource bundle for message localization.
+ * @throws NullPointerException if {@code name} is {@code null} or
+ * {@code bundle} is {@code null}.
+ */
+ @CallerSensitive
+ public static Logger getLogger(String name, ResourceBundle bundle) {
+ final ResourceBundle rb = Objects.requireNonNull(bundle);
+ Objects.requireNonNull(name);
+ final Class<?> caller = Reflection.getCallerClass();
+ final SecurityManager sm = System.getSecurityManager();
+ // We don't use LazyLoggers if a resource bundle is specified.
+ // Bootstrap sensitive classes in the JDK do not use resource bundles
+ // when logging. This could be revisited later, if it needs to.
+ if (sm != null) {
+ return AccessController.doPrivileged((PrivilegedAction<Logger>)
+ () -> LoggerFinder.accessProvider().getLocalizedLogger(name, rb, caller),
+ null,
+ LoggerFinder.LOGGERFINDER_PERMISSION);
+ }
+ return LoggerFinder.accessProvider().getLocalizedLogger(name, rb, caller);
+ }
+
+ /**
* Terminates the currently running Java Virtual Machine. The
* argument serves as a status code; by convention, a nonzero status
* code indicates abnormal termination.
--- a/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java Wed Jul 05 21:02:29 2017 +0200
@@ -224,12 +224,12 @@
assert(names.length == nameCursor);
if (doesAlloc) {
// names = { argx,y,z,... new C, init method }
- names[NEW_OBJ] = new Name(Lazy.NF_allocateInstance, names[DMH_THIS]);
- names[GET_MEMBER] = new Name(Lazy.NF_constructorMethod, names[DMH_THIS]);
+ names[NEW_OBJ] = new Name(NF_allocateInstance, names[DMH_THIS]);
+ names[GET_MEMBER] = new Name(NF_constructorMethod, names[DMH_THIS]);
} else if (needsInit) {
- names[GET_MEMBER] = new Name(Lazy.NF_internalMemberNameEnsureInit, names[DMH_THIS]);
+ names[GET_MEMBER] = new Name(NF_internalMemberNameEnsureInit, names[DMH_THIS]);
} else {
- names[GET_MEMBER] = new Name(Lazy.NF_internalMemberName, names[DMH_THIS]);
+ names[GET_MEMBER] = new Name(NF_internalMemberName, names[DMH_THIS]);
}
assert(findDirectMethodHandle(names[GET_MEMBER]) == names[DMH_THIS]);
Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
@@ -250,9 +250,9 @@
}
static Object findDirectMethodHandle(Name name) {
- if (name.function == Lazy.NF_internalMemberName ||
- name.function == Lazy.NF_internalMemberNameEnsureInit ||
- name.function == Lazy.NF_constructorMethod) {
+ if (name.function == NF_internalMemberName ||
+ name.function == NF_internalMemberNameEnsureInit ||
+ name.function == NF_constructorMethod) {
assert(name.arguments.length == 1);
return name.arguments[0];
}
@@ -613,18 +613,18 @@
final int RESULT = nameCursor-1; // either the call or the cast
Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
if (needsInit)
- names[INIT_BAR] = new Name(Lazy.NF_ensureInitialized, names[DMH_THIS]);
+ names[INIT_BAR] = new Name(NF_ensureInitialized, names[DMH_THIS]);
if (needsCast && !isGetter)
- names[PRE_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
+ names[PRE_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
Object[] outArgs = new Object[1 + linkerType.parameterCount()];
assert(outArgs.length == (isGetter ? 3 : 4));
outArgs[0] = UNSAFE;
if (isStatic) {
- outArgs[1] = names[F_HOLDER] = new Name(Lazy.NF_staticBase, names[DMH_THIS]);
- outArgs[2] = names[F_OFFSET] = new Name(Lazy.NF_staticOffset, names[DMH_THIS]);
+ outArgs[1] = names[F_HOLDER] = new Name(NF_staticBase, names[DMH_THIS]);
+ outArgs[2] = names[F_OFFSET] = new Name(NF_staticOffset, names[DMH_THIS]);
} else {
- outArgs[1] = names[OBJ_CHECK] = new Name(Lazy.NF_checkBase, names[OBJ_BASE]);
- outArgs[2] = names[F_OFFSET] = new Name(Lazy.NF_fieldOffset, names[DMH_THIS]);
+ outArgs[1] = names[OBJ_CHECK] = new Name(NF_checkBase, names[OBJ_BASE]);
+ outArgs[2] = names[F_OFFSET] = new Name(NF_fieldOffset, names[DMH_THIS]);
}
if (!isGetter) {
outArgs[3] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]);
@@ -632,7 +632,7 @@
for (Object a : outArgs) assert(a != null);
names[LINKER_CALL] = new Name(linker, outArgs);
if (needsCast && isGetter)
- names[POST_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[LINKER_CALL]);
+ names[POST_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[LINKER_CALL]);
for (Name n : names) assert(n != null);
String fieldOrStatic = (isStatic ? "Static" : "Field");
String lambdaName = (linkerName + fieldOrStatic); // significant only for debugging
@@ -645,50 +645,45 @@
* Pre-initialized NamedFunctions for bootstrapping purposes.
* Factored in an inner class to delay initialization until first usage.
*/
- private static class Lazy {
- static final NamedFunction
- NF_internalMemberName,
- NF_internalMemberNameEnsureInit,
- NF_ensureInitialized,
- NF_fieldOffset,
- NF_checkBase,
- NF_staticBase,
- NF_staticOffset,
- NF_checkCast,
- NF_allocateInstance,
- NF_constructorMethod;
- static {
- try {
- NamedFunction nfs[] = {
- NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("internalMemberName", Object.class)),
- NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("internalMemberNameEnsureInit", Object.class)),
- NF_ensureInitialized = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("ensureInitialized", Object.class)),
- NF_fieldOffset = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("fieldOffset", Object.class)),
- NF_checkBase = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("checkBase", Object.class)),
- NF_staticBase = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("staticBase", Object.class)),
- NF_staticOffset = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("staticOffset", Object.class)),
- NF_checkCast = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("checkCast", Object.class, Object.class)),
- NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("allocateInstance", Object.class)),
- NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("constructorMethod", Object.class))
- };
- for (NamedFunction nf : nfs) {
- // Each nf must be statically invocable or we get tied up in our bootstraps.
- assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
- nf.resolve();
- }
- } catch (ReflectiveOperationException ex) {
- throw newInternalError(ex);
- }
+ static final NamedFunction
+ NF_internalMemberName,
+ NF_internalMemberNameEnsureInit,
+ NF_ensureInitialized,
+ NF_fieldOffset,
+ NF_checkBase,
+ NF_staticBase,
+ NF_staticOffset,
+ NF_checkCast,
+ NF_allocateInstance,
+ NF_constructorMethod;
+ static {
+ try {
+ NamedFunction nfs[] = {
+ NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("internalMemberName", Object.class)),
+ NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("internalMemberNameEnsureInit", Object.class)),
+ NF_ensureInitialized = new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("ensureInitialized", Object.class)),
+ NF_fieldOffset = new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("fieldOffset", Object.class)),
+ NF_checkBase = new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("checkBase", Object.class)),
+ NF_staticBase = new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("staticBase", Object.class)),
+ NF_staticOffset = new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("staticOffset", Object.class)),
+ NF_checkCast = new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("checkCast", Object.class, Object.class)),
+ NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("allocateInstance", Object.class)),
+ NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
+ .getDeclaredMethod("constructorMethod", Object.class))
+ };
+ // Each nf must be statically invocable or we get tied up in our bootstraps.
+ assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs));
+ } catch (ReflectiveOperationException ex) {
+ throw newInternalError(ex);
}
}
}
--- a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Wed Jul 05 21:02:29 2017 +0200
@@ -750,7 +750,7 @@
assert(!isLinkerMethodInvoke(name)); // should use the static path for these
if (true) {
// push receiver
- MethodHandle target = name.function.resolvedHandle;
+ MethodHandle target = name.function.resolvedHandle();
assert(target != null) : name.exprString();
mv.visitLdcInsn(constantPlaceholder(target));
emitReferenceCast(MethodHandle.class, target);
@@ -779,6 +779,15 @@
//MethodHandle.class already covered
};
+ static boolean isStaticallyInvocable(NamedFunction[] functions) {
+ for (NamedFunction nf : functions) {
+ if (!isStaticallyInvocable(nf.member())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
static boolean isStaticallyInvocable(Name name) {
return isStaticallyInvocable(name.function.member());
}
@@ -881,7 +890,7 @@
// The array will be a constant.
Object emptyArray;
try {
- emptyArray = name.function.resolvedHandle.invoke();
+ emptyArray = name.function.resolvedHandle().invoke();
} catch (Throwable ex) {
throw newInternalError(ex);
}
@@ -1085,8 +1094,8 @@
Label L_handler = new Label();
Label L_done = new Label();
- Class<?> returnType = result.function.resolvedHandle.type().returnType();
- MethodType type = args.function.resolvedHandle.type()
+ Class<?> returnType = result.function.resolvedHandle().type().returnType();
+ MethodType type = args.function.resolvedHandle().type()
.dropParameterTypes(0,1)
.changeReturnType(returnType);
--- a/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java Wed Jul 05 21:02:29 2017 +0200
@@ -429,11 +429,8 @@
NF_checkCustomized = new NamedFunction(Invokers.class
.getDeclaredMethod("checkCustomized", Object.class))
};
- for (NamedFunction nf : nfs) {
- // Each nf must be statically invocable or we get tied up in our bootstraps.
- assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
- nf.resolve();
- }
+ // Each nf must be statically invocable or we get tied up in our bootstraps.
+ assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs));
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
--- a/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java Wed Jul 05 21:02:29 2017 +0200
@@ -1024,7 +1024,7 @@
static class NamedFunction {
final MemberName member;
- @Stable MethodHandle resolvedHandle;
+ private @Stable MethodHandle resolvedHandle;
@Stable MethodHandle invoker;
NamedFunction(MethodHandle resolvedHandle) {
@@ -1074,8 +1074,10 @@
return resolvedHandle;
}
- void resolve() {
- resolvedHandle = DirectMethodHandle.make(member);
+ synchronized void resolve() {
+ if (resolvedHandle == null) {
+ resolvedHandle = DirectMethodHandle.make(member);
+ }
}
@Override
@@ -1235,6 +1237,7 @@
traceInterpreter("| getInvoker", this);
invoker();
}
+ // resolvedHandle might be uninitialized, ok for tracing
if (resolvedHandle == null) {
traceInterpreter("| resolve", this);
resolvedHandle();
@@ -1704,88 +1707,112 @@
private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
static LambdaForm identityForm(BasicType type) {
- return LF_identityForm[type.ordinal()];
- }
- static LambdaForm zeroForm(BasicType type) {
- return LF_zeroForm[type.ordinal()];
+ int ord = type.ordinal();
+ LambdaForm form = LF_identity[ord];
+ if (form != null) {
+ return form;
+ }
+ createFormsFor(type);
+ return LF_identity[ord];
}
- static NamedFunction identity(BasicType type) {
- return NF_identity[type.ordinal()];
+
+ static LambdaForm zeroForm(BasicType type) {
+ int ord = type.ordinal();
+ LambdaForm form = LF_zero[ord];
+ if (form != null) {
+ return form;
+ }
+ createFormsFor(type);
+ return LF_zero[ord];
}
- static NamedFunction constantZero(BasicType type) {
- return NF_zero[type.ordinal()];
+
+ static NamedFunction identity(BasicType type) {
+ int ord = type.ordinal();
+ NamedFunction function = NF_identity[ord];
+ if (function != null) {
+ return function;
+ }
+ createFormsFor(type);
+ return NF_identity[ord];
}
- private static final LambdaForm[] LF_identityForm = new LambdaForm[TYPE_LIMIT];
- private static final LambdaForm[] LF_zeroForm = new LambdaForm[TYPE_LIMIT];
- private static final NamedFunction[] NF_identity = new NamedFunction[TYPE_LIMIT];
- private static final NamedFunction[] NF_zero = new NamedFunction[TYPE_LIMIT];
- private static void createIdentityForms() {
- for (BasicType type : BasicType.ALL_TYPES) {
- int ord = type.ordinal();
- char btChar = type.basicTypeChar();
- boolean isVoid = (type == V_TYPE);
- Class<?> btClass = type.btClass;
- MethodType zeType = MethodType.methodType(btClass);
- MethodType idType = isVoid ? zeType : zeType.appendParameterTypes(btClass);
+
+ static NamedFunction constantZero(BasicType type) {
+ int ord = type.ordinal();
+ NamedFunction function = NF_zero[ord];
+ if (function != null) {
+ return function;
+ }
+ createFormsFor(type);
+ return NF_zero[ord];
+ }
+
+ private static final @Stable LambdaForm[] LF_identity = new LambdaForm[TYPE_LIMIT];
+ private static final @Stable LambdaForm[] LF_zero = new LambdaForm[TYPE_LIMIT];
+ private static final @Stable NamedFunction[] NF_identity = new NamedFunction[TYPE_LIMIT];
+ private static final @Stable NamedFunction[] NF_zero = new NamedFunction[TYPE_LIMIT];
- // Look up some symbolic names. It might not be necessary to have these,
- // but if we need to emit direct references to bytecodes, it helps.
- // Zero is built from a call to an identity function with a constant zero input.
- MemberName idMem = new MemberName(LambdaForm.class, "identity_"+btChar, idType, REF_invokeStatic);
- MemberName zeMem = new MemberName(LambdaForm.class, "zero_"+btChar, zeType, REF_invokeStatic);
- try {
+ private static synchronized void createFormsFor(BasicType type) {
+ final int ord = type.ordinal();
+ LambdaForm idForm = LF_identity[ord];
+ if (idForm != null) {
+ return;
+ }
+ char btChar = type.basicTypeChar();
+ boolean isVoid = (type == V_TYPE);
+ Class<?> btClass = type.btClass;
+ MethodType zeType = MethodType.methodType(btClass);
+ MethodType idType = (isVoid) ? zeType : zeType.appendParameterTypes(btClass);
+
+ // Look up symbolic names. It might not be necessary to have these,
+ // but if we need to emit direct references to bytecodes, it helps.
+ // Zero is built from a call to an identity function with a constant zero input.
+ MemberName idMem = new MemberName(LambdaForm.class, "identity_"+btChar, idType, REF_invokeStatic);
+ MemberName zeMem = null;
+ try {
+ idMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, idMem, null, NoSuchMethodException.class);
+ if (!isVoid) {
+ zeMem = new MemberName(LambdaForm.class, "zero_"+btChar, zeType, REF_invokeStatic);
zeMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zeMem, null, NoSuchMethodException.class);
- idMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, idMem, null, NoSuchMethodException.class);
- } catch (IllegalAccessException|NoSuchMethodException ex) {
- throw newInternalError(ex);
}
-
- NamedFunction idFun = new NamedFunction(idMem);
- LambdaForm idForm;
- if (isVoid) {
- Name[] idNames = new Name[] { argument(0, L_TYPE) };
- idForm = new LambdaForm(idMem.getName(), 1, idNames, VOID_RESULT);
- } else {
- Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) };
- idForm = new LambdaForm(idMem.getName(), 2, idNames, 1);
- }
- LF_identityForm[ord] = idForm;
- NF_identity[ord] = idFun;
-
- NamedFunction zeFun = new NamedFunction(zeMem);
- LambdaForm zeForm;
- if (isVoid) {
- zeForm = idForm;
- } else {
- Object zeValue = Wrapper.forBasicType(btChar).zero();
- Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) };
- zeForm = new LambdaForm(zeMem.getName(), 1, zeNames, 1);
- }
- LF_zeroForm[ord] = zeForm;
- NF_zero[ord] = zeFun;
-
- assert(idFun.isIdentity());
- assert(zeFun.isConstantZero());
- assert(new Name(zeFun).isConstantZero());
+ } catch (IllegalAccessException|NoSuchMethodException ex) {
+ throw newInternalError(ex);
}
- // Do this in a separate pass, so that SimpleMethodHandle.make can see the tables.
- for (BasicType type : BasicType.ALL_TYPES) {
- int ord = type.ordinal();
- NamedFunction idFun = NF_identity[ord];
- LambdaForm idForm = LF_identityForm[ord];
- MemberName idMem = idFun.member;
- idFun.resolvedHandle = SimpleMethodHandle.make(idMem.getInvocationType(), idForm);
+ NamedFunction idFun;
+ LambdaForm zeForm;
+ NamedFunction zeFun;
+
+ // Create the LFs and NamedFunctions. Precompiling LFs to byte code is needed to break circular
+ // bootstrap dependency on this method in case we're interpreting LFs
+ if (isVoid) {
+ Name[] idNames = new Name[] { argument(0, L_TYPE) };
+ idForm = new LambdaForm(idMem.getName(), 1, idNames, VOID_RESULT);
+ idForm.compileToBytecode();
+ idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm));
- NamedFunction zeFun = NF_zero[ord];
- LambdaForm zeForm = LF_zeroForm[ord];
- MemberName zeMem = zeFun.member;
- zeFun.resolvedHandle = SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm);
+ zeForm = idForm;
+ zeFun = idFun;
+ } else {
+ Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) };
+ idForm = new LambdaForm(idMem.getName(), 2, idNames, 1);
+ idForm.compileToBytecode();
+ idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm));
- assert(idFun.isIdentity());
- assert(zeFun.isConstantZero());
- assert(new Name(zeFun).isConstantZero());
+ Object zeValue = Wrapper.forBasicType(btChar).zero();
+ Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) };
+ zeForm = new LambdaForm(zeMem.getName(), 1, zeNames, 1);
+ zeForm.compileToBytecode();
+ zeFun = new NamedFunction(zeMem, SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm));
}
+
+ LF_zero[ord] = zeForm;
+ NF_zero[ord] = zeFun;
+ LF_identity[ord] = idForm;
+ NF_identity[ord] = idFun;
+
+ assert(idFun.isIdentity());
+ assert(zeFun.isConstantZero());
+ assert(new Name(zeFun).isConstantZero());
}
// Avoid appealing to ValueConversions at bootstrap time:
@@ -1794,13 +1821,12 @@
private static float identity_F(float x) { return x; }
private static double identity_D(double x) { return x; }
private static Object identity_L(Object x) { return x; }
- private static void identity_V() { return; } // same as zeroV, but that's OK
+ private static void identity_V() { return; }
private static int zero_I() { return 0; }
private static long zero_J() { return 0; }
private static float zero_F() { return 0; }
private static double zero_D() { return 0; }
private static Object zero_L() { return null; }
- private static void zero_V() { return; }
/**
* Internal marker for byte-compiled LambdaForms.
@@ -1830,7 +1856,6 @@
// Put this last, so that previous static inits can run before.
static {
- createIdentityForms();
if (USE_PREDEFINED_INTERPRET_METHODS)
computeInitialPreparedForms();
NamedFunction.initializeInvokers();
--- a/jdk/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java Wed Jul 05 21:02:29 2017 +0200
@@ -541,7 +541,7 @@
assert(pos > 0); // cannot spread the MH arg itself
Name spreadParam = new Name(L_TYPE);
- Name checkSpread = new Name(MethodHandleImpl.Lazy.NF_checkSpreadArgument, spreadParam, arrayLength);
+ Name checkSpread = new Name(MethodHandleImpl.NF_checkSpreadArgument, spreadParam, arrayLength);
// insert the new expressions
int exprPos = lambdaForm.arity();
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java Wed Jul 05 21:02:29 2017 +0200
@@ -872,13 +872,54 @@
* @see #asCollector
*/
public MethodHandle asSpreader(Class<?> arrayType, int arrayLength) {
- MethodType postSpreadType = asSpreaderChecks(arrayType, arrayLength);
- int arity = type().parameterCount();
- int spreadArgPos = arity - arrayLength;
+ return asSpreader(type().parameterCount() - arrayLength, arrayType, arrayLength);
+ }
+
+ /**
+ * Makes an <em>array-spreading</em> method handle, which accepts an array argument at a given position and spreads
+ * its elements as positional arguments in place of the array. The new method handle adapts, as its <i>target</i>,
+ * the current method handle. The type of the adapter will be the same as the type of the target, except that the
+ * {@code arrayLength} parameters of the target's type, starting at the zero-based position {@code spreadArgPos},
+ * are replaced by a single array parameter of type {@code arrayType}.
+ * <p>
+ * This method behaves very much like {@link #asSpreader(Class, int)}, but accepts an additional {@code spreadArgPos}
+ * argument to indicate at which position in the parameter list the spreading should take place.
+ * <p>
+ * @apiNote Example:
+ * <blockquote><pre>{@code
+ MethodHandle compare = LOOKUP.findStatic(Objects.class, "compare", methodType(int.class, Object.class, Object.class, Comparator.class));
+ MethodHandle compare2FromArray = compare.asSpreader(0, Object[].class, 2);
+ Object[] ints = new Object[]{3, 9, 7, 7};
+ Comparator<Integer> cmp = (a, b) -> a - b;
+ assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 0, 2), cmp) < 0);
+ assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 1, 3), cmp) > 0);
+ assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 2, 4), cmp) == 0);
+ * }</pre></blockquote>
+ * @param spreadArgPos the position (zero-based index) in the argument list at which spreading should start.
+ * @param arrayType usually {@code Object[]}, the type of the array argument from which to extract the spread arguments
+ * @param arrayLength the number of arguments to spread from an incoming array argument
+ * @return a new method handle which spreads an array argument at a given position,
+ * before calling the original method handle
+ * @throws NullPointerException if {@code arrayType} is a null reference
+ * @throws IllegalArgumentException if {@code arrayType} is not an array type,
+ * or if target does not have at least
+ * {@code arrayLength} parameter types,
+ * or if {@code arrayLength} is negative,
+ * or if {@code spreadArgPos} has an illegal value (negative, or together with arrayLength exceeding the
+ * number of arguments),
+ * or if the resulting method handle's type would have
+ * <a href="MethodHandle.html#maxarity">too many parameters</a>
+ * @throws WrongMethodTypeException if the implied {@code asType} call fails
+ *
+ * @see #asSpreader(Class, int)
+ * @since 9
+ */
+ public MethodHandle asSpreader(int spreadArgPos, Class<?> arrayType, int arrayLength) {
+ MethodType postSpreadType = asSpreaderChecks(arrayType, spreadArgPos, arrayLength);
MethodHandle afterSpread = this.asType(postSpreadType);
BoundMethodHandle mh = afterSpread.rebind();
LambdaForm lform = mh.editor().spreadArgumentsForm(1 + spreadArgPos, arrayType, arrayLength);
- MethodType preSpreadType = postSpreadType.replaceParameterTypes(spreadArgPos, arity, arrayType);
+ MethodType preSpreadType = postSpreadType.replaceParameterTypes(spreadArgPos, spreadArgPos + arrayLength, arrayType);
return mh.copyWith(preSpreadType, lform);
}
@@ -886,15 +927,18 @@
* See if {@code asSpreader} can be validly called with the given arguments.
* Return the type of the method handle call after spreading but before conversions.
*/
- private MethodType asSpreaderChecks(Class<?> arrayType, int arrayLength) {
+ private MethodType asSpreaderChecks(Class<?> arrayType, int pos, int arrayLength) {
spreadArrayChecks(arrayType, arrayLength);
int nargs = type().parameterCount();
if (nargs < arrayLength || arrayLength < 0)
throw newIllegalArgumentException("bad spread array length");
+ if (pos < 0 || pos + arrayLength > nargs) {
+ throw newIllegalArgumentException("bad spread position");
+ }
Class<?> arrayElement = arrayType.getComponentType();
MethodType mtype = type();
boolean match = true, fail = false;
- for (int i = nargs - arrayLength; i < nargs; i++) {
+ for (int i = pos; i < arrayLength; i++) {
Class<?> ptype = mtype.parameterType(i);
if (ptype != arrayElement) {
match = false;
@@ -905,7 +949,7 @@
}
}
if (match) return mtype;
- MethodType needType = mtype.asSpreaderType(arrayType, arrayLength);
+ MethodType needType = mtype.asSpreaderType(arrayType, pos, arrayLength);
if (!fail) return needType;
// elicit an error:
this.asType(needType);
@@ -998,10 +1042,53 @@
* @see #asVarargsCollector
*/
public MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
- asCollectorChecks(arrayType, arrayLength);
- int collectArgPos = type().parameterCount() - 1;
+ return asCollector(type().parameterCount() - 1, arrayType, arrayLength);
+ }
+
+ /**
+ * Makes an <em>array-collecting</em> method handle, which accepts a given number of positional arguments starting
+ * at a given position, and collects them into an array argument. The new method handle adapts, as its
+ * <i>target</i>, the current method handle. The type of the adapter will be the same as the type of the target,
+ * except that the parameter at the position indicated by {@code collectArgPos} (usually of type {@code arrayType})
+ * is replaced by {@code arrayLength} parameters whose type is element type of {@code arrayType}.
+ * <p>
+ * This method behaves very much like {@link #asCollector(Class, int)}, but differs in that its {@code
+ * collectArgPos} argument indicates at which position in the parameter list arguments should be collected. This
+ * index is zero-based.
+ * <p>
+ * @apiNote Examples:
+ * <blockquote><pre>{@code
+ StringWriter swr = new StringWriter();
+ MethodHandle swWrite = LOOKUP.findVirtual(StringWriter.class, "write", methodType(void.class, char[].class, int.class, int.class)).bindTo(swr);
+ MethodHandle swWrite4 = swWrite.asCollector(0, char[].class, 4);
+ swWrite4.invoke('A', 'B', 'C', 'D', 1, 2);
+ assertEquals("BC", swr.toString());
+ swWrite4.invoke('P', 'Q', 'R', 'S', 0, 4);
+ assertEquals("BCPQRS", swr.toString());
+ swWrite4.invoke('W', 'X', 'Y', 'Z', 3, 1);
+ assertEquals("BCPQRSZ", swr.toString());
+ * }</pre></blockquote>
+ * @param collectArgPos the zero-based position in the parameter list at which to start collecting.
+ * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
+ * @param arrayLength the number of arguments to collect into a new array argument
+ * @return a new method handle which collects some arguments
+ * into an array, before calling the original method handle
+ * @throws NullPointerException if {@code arrayType} is a null reference
+ * @throws IllegalArgumentException if {@code arrayType} is not an array type
+ * or {@code arrayType} is not assignable to this method handle's array parameter type,
+ * or {@code arrayLength} is not a legal array size,
+ * or {@code collectArgPos} has an illegal value (negative, or greater than the number of arguments),
+ * or the resulting method handle's type would have
+ * <a href="MethodHandle.html#maxarity">too many parameters</a>
+ * @throws WrongMethodTypeException if the implied {@code asType} call fails
+ *
+ * @see #asCollector(Class, int)
+ * @since 9
+ */
+ public MethodHandle asCollector(int collectArgPos, Class<?> arrayType, int arrayLength) {
+ asCollectorChecks(arrayType, collectArgPos, arrayLength);
BoundMethodHandle mh = rebind();
- MethodType resultType = type().asCollectorType(arrayType, arrayLength);
+ MethodType resultType = type().asCollectorType(arrayType, collectArgPos, arrayLength);
MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength);
LambdaForm lform = mh.editor().collectArgumentArrayForm(1 + collectArgPos, newArray);
if (lform != null) {
@@ -1015,15 +1102,18 @@
* See if {@code asCollector} can be validly called with the given arguments.
* Return false if the last parameter is not an exact match to arrayType.
*/
- /*non-public*/ boolean asCollectorChecks(Class<?> arrayType, int arrayLength) {
+ /*non-public*/ boolean asCollectorChecks(Class<?> arrayType, int pos, int arrayLength) {
spreadArrayChecks(arrayType, arrayLength);
int nargs = type().parameterCount();
+ if (pos < 0 || pos >= nargs) {
+ throw newIllegalArgumentException("bad collect position");
+ }
if (nargs != 0) {
- Class<?> lastParam = type().parameterType(nargs-1);
- if (lastParam == arrayType) return true;
- if (lastParam.isAssignableFrom(arrayType)) return false;
+ Class<?> param = type().parameterType(pos);
+ if (param == arrayType) return true;
+ if (param.isAssignableFrom(arrayType)) return false;
}
- throw newIllegalArgumentException("array type not assignable to trailing argument", this, arrayType);
+ throw newIllegalArgumentException("array type not assignable to argument", this, arrayType);
}
/**
@@ -1178,7 +1268,7 @@
*/
public MethodHandle asVarargsCollector(Class<?> arrayType) {
Objects.requireNonNull(arrayType);
- boolean lastMatch = asCollectorChecks(arrayType, 0);
+ boolean lastMatch = asCollectorChecks(arrayType, type().parameterCount() - 1, 0);
if (isVarargsCollector() && lastMatch)
return this;
return MethodHandleImpl.makeVarargsCollector(this, arrayType);
@@ -1341,7 +1431,6 @@
// cannot be cracked into MethodHandleInfo.
assert viewAsTypeChecks(newType, strict);
BoundMethodHandle mh = rebind();
- assert(!((MethodHandle)mh instanceof DirectMethodHandle));
return mh.copyWith(newType, mh.form);
}
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,16 +27,17 @@
import java.security.AccessController;
import java.security.PrivilegedAction;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
import java.util.function.Function;
+import java.util.stream.Collectors;
import sun.invoke.empty.Empty;
import sun.invoke.util.ValueConversions;
import sun.invoke.util.VerifyType;
import sun.invoke.util.Wrapper;
-import jdk.internal.HotSpotIntrinsicCandidate;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import static java.lang.invoke.LambdaForm.*;
@@ -219,7 +220,7 @@
if (convSpec == null) continue;
MethodHandle fn;
if (convSpec instanceof Class) {
- fn = Lazy.MH_cast.bindTo(convSpec);
+ fn = getConstantHandle(MH_cast).bindTo(convSpec);
} else {
fn = (MethodHandle) convSpec;
}
@@ -239,7 +240,7 @@
if (convSpec == void.class)
fn = null;
else
- fn = Lazy.MH_cast.bindTo(convSpec);
+ fn = getConstantHandle(MH_cast).bindTo(convSpec);
} else {
fn = (MethodHandle) convSpec;
}
@@ -302,7 +303,7 @@
Name conv;
if (convSpec instanceof Class) {
Class<?> convClass = (Class<?>) convSpec;
- conv = new Name(Lazy.MH_cast, convClass, names[INARG_BASE + i]);
+ conv = new Name(getConstantHandle(MH_cast), convClass, names[INARG_BASE + i]);
} else {
MethodHandle fn = (MethodHandle) convSpec;
conv = new Name(fn, names[INARG_BASE + i]);
@@ -326,7 +327,7 @@
conv = new Name(LambdaForm.constantZero(BasicType.basicType(srcType.returnType())));
} else if (convSpec instanceof Class) {
Class<?> convClass = (Class<?>) convSpec;
- conv = new Name(Lazy.MH_cast, convClass, names[OUT_CALL]);
+ conv = new Name(getConstantHandle(MH_cast), convClass, names[OUT_CALL]);
} else {
MethodHandle fn = (MethodHandle) convSpec;
if (fn.type().parameterCount() == 0)
@@ -529,7 +530,7 @@
// Spread the array.
MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType);
Name array = names[argIndex];
- names[nameCursor++] = new Name(Lazy.NF_checkSpreadArgument, array, spreadArgCount);
+ names[nameCursor++] = new Name(NF_checkSpreadArgument, array, spreadArgCount);
for (int j = 0; j < spreadArgCount; i++, j++) {
indexes[i] = nameCursor;
names[nameCursor++] = new Name(aload, array, j);
@@ -566,66 +567,6 @@
throw newIllegalArgumentException("array is not of length "+n);
}
- /**
- * Pre-initialized NamedFunctions for bootstrapping purposes.
- * Factored in an inner class to delay initialization until first usage.
- */
- static class Lazy {
- private static final Class<?> MHI = MethodHandleImpl.class;
- private static final Class<?> CLS = Class.class;
-
- private static final MethodHandle[] ARRAYS;
- private static final MethodHandle[] FILL_ARRAYS;
-
- static final NamedFunction NF_checkSpreadArgument;
- static final NamedFunction NF_guardWithCatch;
- static final NamedFunction NF_throwException;
- static final NamedFunction NF_profileBoolean;
-
- static final MethodHandle MH_cast;
- static final MethodHandle MH_selectAlternative;
- static final MethodHandle MH_copyAsPrimitiveArray;
- static final MethodHandle MH_fillNewTypedArray;
- static final MethodHandle MH_fillNewArray;
- static final MethodHandle MH_arrayIdentity;
-
- static {
- ARRAYS = makeArrays();
- FILL_ARRAYS = makeFillArrays();
-
- try {
- NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
- NF_guardWithCatch = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
- MethodHandle.class, Object[].class));
- NF_throwException = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class));
- NF_profileBoolean = new NamedFunction(MHI.getDeclaredMethod("profileBoolean", boolean.class, int[].class));
-
- NF_checkSpreadArgument.resolve();
- NF_guardWithCatch.resolve();
- NF_throwException.resolve();
- NF_profileBoolean.resolve();
-
- MH_cast = IMPL_LOOKUP.findVirtual(CLS, "cast",
- MethodType.methodType(Object.class, Object.class));
- MH_copyAsPrimitiveArray = IMPL_LOOKUP.findStatic(MHI, "copyAsPrimitiveArray",
- MethodType.methodType(Object.class, Wrapper.class, Object[].class));
- MH_arrayIdentity = IMPL_LOOKUP.findStatic(MHI, "identity",
- MethodType.methodType(Object[].class, Object[].class));
- MH_fillNewArray = IMPL_LOOKUP.findStatic(MHI, "fillNewArray",
- MethodType.methodType(Object[].class, Integer.class, Object[].class));
- MH_fillNewTypedArray = IMPL_LOOKUP.findStatic(MHI, "fillNewTypedArray",
- MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
-
- MH_selectAlternative = makeIntrinsic(
- IMPL_LOOKUP.findStatic(MHI, "selectAlternative",
- MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)),
- Intrinsic.SELECT_ALTERNATIVE);
- } catch (ReflectiveOperationException ex) {
- throw newInternalError(ex);
- }
- }
- }
-
/** Factory method: Collect or filter selected argument(s). */
static MethodHandle makeCollectArguments(MethodHandle target,
MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) {
@@ -911,10 +852,10 @@
// profile branch
if (PROFILE != -1) {
- names[PROFILE] = new Name(Lazy.NF_profileBoolean, names[CALL_TEST], names[GET_COUNTERS]);
+ names[PROFILE] = new Name(NF_profileBoolean, names[CALL_TEST], names[GET_COUNTERS]);
}
// call selectAlternative
- names[SELECT_ALT] = new Name(Lazy.MH_selectAlternative, names[TEST], names[GET_TARGET], names[GET_FALLBACK]);
+ names[SELECT_ALT] = new Name(getConstantHandle(MH_selectAlternative), names[TEST], names[GET_TARGET], names[GET_FALLBACK]);
// call target or fallback
invokeArgs[0] = names[SELECT_ALT];
@@ -989,7 +930,7 @@
// t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L);
Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]};
- names[TRY_CATCH] = new Name(Lazy.NF_guardWithCatch, gwcArgs);
+ names[TRY_CATCH] = new Name(NF_guardWithCatch, gwcArgs);
// t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L);
MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class));
@@ -1073,7 +1014,7 @@
mh = MethodHandles.dropArguments(mh, 1, type.parameterList().subList(1, arity));
return mh;
}
- return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, false, true);
+ return makePairwiseConvert(NF_throwException.resolvedHandle(), type, false, true);
}
static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
@@ -1357,7 +1298,7 @@
@Override
public MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
if (intrinsicName == Intrinsic.IDENTITY) {
- MethodType resultType = type().asCollectorType(arrayType, arrayLength);
+ MethodType resultType = type().asCollectorType(arrayType, type().parameterCount() - 1, arrayLength);
MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength);
return newArray.asType(resultType);
}
@@ -1421,25 +1362,7 @@
{ return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
private static final int ARRAYS_COUNT = 11;
-
- private static MethodHandle[] makeArrays() {
- MethodHandle[] mhs = new MethodHandle[MAX_ARITY + 1];
- for (int i = 0; i < ARRAYS_COUNT; i++) {
- MethodHandle mh = findCollector("array", i, Object[].class);
- mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
- mhs[i] = mh;
- }
- assert(assertArrayMethodCount(mhs));
- return mhs;
- }
-
- private static boolean assertArrayMethodCount(MethodHandle[] mhs) {
- assert(findCollector("array", ARRAYS_COUNT, Object[].class) == null);
- for (int i = 0; i < ARRAYS_COUNT; i++) {
- assert(mhs[i] != null);
- }
- return true;
- }
+ private static final @Stable MethodHandle[] ARRAYS = new MethodHandle[MAX_ARITY + 1];
// filling versions of the above:
// using Integer len instead of int len and no varargs to avoid bootstrapping problems
@@ -1488,24 +1411,17 @@
{ fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; }
private static final int FILL_ARRAYS_COUNT = 11; // current number of fillArray methods
+ private static final @Stable MethodHandle[] FILL_ARRAYS = new MethodHandle[FILL_ARRAYS_COUNT];
- private static MethodHandle[] makeFillArrays() {
- MethodHandle[] mhs = new MethodHandle[FILL_ARRAYS_COUNT];
- mhs[0] = null; // there is no empty fill; at least a0 is required
- for (int i = 1; i < FILL_ARRAYS_COUNT; i++) {
- MethodHandle mh = findCollector("fillArray", i, Object[].class, Integer.class, Object[].class);
- mhs[i] = mh;
+ private static MethodHandle getFillArray(int count) {
+ assert (count > 0 && count < FILL_ARRAYS_COUNT);
+ MethodHandle mh = FILL_ARRAYS[count];
+ if (mh != null) {
+ return mh;
}
- assert(assertFillArrayMethodCount(mhs));
- return mhs;
- }
-
- private static boolean assertFillArrayMethodCount(MethodHandle[] mhs) {
- assert(findCollector("fillArray", FILL_ARRAYS_COUNT, Object[].class, Integer.class, Object[].class) == null);
- for (int i = 1; i < FILL_ARRAYS_COUNT; i++) {
- assert(mhs[i] != null);
- }
- return true;
+ mh = findCollector("fillArray", count, Object[].class, Integer.class, Object[].class);
+ FILL_ARRAYS[count] = mh;
+ return mh;
}
private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) {
@@ -1518,12 +1434,19 @@
* arguments and returns an Object array of them, as if for varargs.
*/
static MethodHandle varargsArray(int nargs) {
- MethodHandle mh = Lazy.ARRAYS[nargs];
- if (mh != null) return mh;
- mh = buildVarargsArray(Lazy.MH_fillNewArray, Lazy.MH_arrayIdentity, nargs);
+ MethodHandle mh = ARRAYS[nargs];
+ if (mh != null) {
+ return mh;
+ }
+ if (nargs < ARRAYS_COUNT) {
+ mh = findCollector("array", nargs, Object[].class);
+ } else {
+ mh = buildVarargsArray(getConstantHandle(MH_fillNewArray),
+ getConstantHandle(MH_arrayIdentity), nargs);
+ }
assert(assertCorrectArity(mh, nargs));
mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
- return Lazy.ARRAYS[nargs] = mh;
+ return ARRAYS[nargs] = mh;
}
private static boolean assertCorrectArity(MethodHandle mh, int arity) {
@@ -1531,7 +1454,7 @@
return true;
}
- // Array identity function (used as Lazy.MH_arrayIdentity).
+ // Array identity function (used as getConstantHandle(MH_arrayIdentity)).
static <T> T[] identity(T[] x) {
return x;
}
@@ -1547,12 +1470,12 @@
MethodHandle mh = finisher;
if (rightLen > 0) {
MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen);
- if (mh == Lazy.MH_arrayIdentity)
+ if (mh.equals(getConstantHandle(MH_arrayIdentity)))
mh = rightFiller;
else
mh = MethodHandles.collectArguments(mh, 0, rightFiller);
}
- if (mh == Lazy.MH_arrayIdentity)
+ if (mh.equals(getConstantHandle(MH_arrayIdentity)))
mh = leftCollector;
else
mh = MethodHandles.collectArguments(mh, 0, leftCollector);
@@ -1560,7 +1483,7 @@
}
private static final int LEFT_ARGS = FILL_ARRAYS_COUNT - 1;
- private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1];
+ private static final @Stable MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1];
/** fill_array_to_right(N).invoke(a, argL..arg[N-1])
* fills a[L]..a[N-1] with corresponding arguments,
* and then returns a. The value L is a global constant (LEFT_ARGS).
@@ -1574,7 +1497,7 @@
}
private static MethodHandle buildFiller(int nargs) {
if (nargs <= LEFT_ARGS)
- return Lazy.MH_arrayIdentity; // no args to fill; return the array unchanged
+ return getConstantHandle(MH_arrayIdentity); // no args to fill; return the array unchanged
// we need room for both mh and a in mh.invoke(a, arg*[nargs])
final int CHUNK = LEFT_ARGS;
int rightLen = nargs % CHUNK;
@@ -1590,7 +1513,7 @@
if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS);
assert(rightLen > 0);
MethodHandle midFill = fillToRight(midLen); // recursive fill
- MethodHandle rightFill = Lazy.FILL_ARRAYS[rightLen].bindTo(midLen); // [midLen..nargs-1]
+ MethodHandle rightFill = getFillArray(rightLen).bindTo(midLen); // [midLen..nargs-1]
assert(midFill.type().parameterCount() == 1 + midLen - LEFT_ARGS);
assert(rightFill.type().parameterCount() == 1 + rightLen);
@@ -1641,14 +1564,14 @@
Object example = java.lang.reflect.Array.newInstance(arrayType.getComponentType(), 0);
mh = MethodHandles.constant(arrayType, example);
} else if (elemType.isPrimitive()) {
- MethodHandle builder = Lazy.MH_fillNewArray;
+ MethodHandle builder = getConstantHandle(MH_fillNewArray);
MethodHandle producer = buildArrayProducer(arrayType);
mh = buildVarargsArray(builder, producer, nargs);
} else {
Class<? extends Object[]> objArrayType = arrayType.asSubclass(Object[].class);
Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType);
- MethodHandle builder = Lazy.MH_fillNewTypedArray.bindTo(example);
- MethodHandle producer = Lazy.MH_arrayIdentity; // must be weakly typed
+ MethodHandle builder = getConstantHandle(MH_fillNewTypedArray).bindTo(example);
+ MethodHandle producer = getConstantHandle(MH_arrayIdentity); // must be weakly typed
mh = buildVarargsArray(builder, producer, nargs);
}
mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
@@ -1662,7 +1585,7 @@
private static MethodHandle buildArrayProducer(Class<?> arrayType) {
Class<?> elemType = arrayType.getComponentType();
assert(elemType.isPrimitive());
- return Lazy.MH_copyAsPrimitiveArray.bindTo(Wrapper.forPrimitiveType(elemType));
+ return getConstantHandle(MH_copyAsPrimitiveArray).bindTo(Wrapper.forPrimitiveType(elemType));
}
/*non-public*/ static void assertSame(Object mh1, Object mh2) {
@@ -1673,4 +1596,346 @@
throw newInternalError(msg);
}
}
+
+ // Local constant functions:
+ /*non-public*/ static final NamedFunction
+ NF_checkSpreadArgument,
+ NF_guardWithCatch,
+ NF_throwException,
+ NF_profileBoolean;
+
+ static {
+ try {
+ NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class
+ .getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
+ NF_guardWithCatch = new NamedFunction(MethodHandleImpl.class
+ .getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
+ MethodHandle.class, Object[].class));
+ NF_throwException = new NamedFunction(MethodHandleImpl.class
+ .getDeclaredMethod("throwException", Throwable.class));
+ NF_profileBoolean = new NamedFunction(MethodHandleImpl.class
+ .getDeclaredMethod("profileBoolean", boolean.class, int[].class));
+ } catch (ReflectiveOperationException ex) {
+ throw newInternalError(ex);
+ }
+ }
+
+ /**
+ * Assembles a loop method handle from the given handles and type information. This works by binding and configuring
+ * the {@linkplain #looper(MethodHandle[], MethodHandle[], MethodHandle[], MethodHandle[], int, int, Object[]) "most
+ * generic loop"}.
+ *
+ * @param tloop the return type of the loop.
+ * @param targs types of the arguments to be passed to the loop.
+ * @param tvars types of loop-local variables.
+ * @param init sanitized array of initializers for loop-local variables.
+ * @param step sanitited array of loop bodies.
+ * @param pred sanitized array of predicates.
+ * @param fini sanitized array of loop finalizers.
+ *
+ * @return a handle that, when invoked, will execute the loop.
+ */
+ static MethodHandle makeLoop(Class<?> tloop, List<Class<?>> targs, List<Class<?>> tvars, List<MethodHandle> init,
+ List<MethodHandle> step, List<MethodHandle> pred, List<MethodHandle> fini) {
+ MethodHandle[] ainit = toArrayArgs(init);
+ MethodHandle[] astep = toArrayArgs(step);
+ MethodHandle[] apred = toArrayArgs(pred);
+ MethodHandle[] afini = toArrayArgs(fini);
+
+ MethodHandle l = getConstantHandle(MH_looper);
+
+ // Bind the statically known arguments.
+ l = MethodHandles.insertArguments(l, 0, ainit, astep, apred, afini, tvars.size(), targs.size());
+
+ // Turn the args array into an argument list.
+ l = l.asCollector(Object[].class, targs.size());
+
+ // Finally, make loop type.
+ MethodType loopType = MethodType.methodType(tloop, targs);
+ l = l.asType(loopType);
+
+ return l;
+ }
+
+ /**
+ * Converts all handles in the {@code hs} array to handles that accept an array of arguments.
+ *
+ * @param hs method handles to be converted.
+ *
+ * @return the {@code hs} array, with all method handles therein converted.
+ */
+ static MethodHandle[] toArrayArgs(List<MethodHandle> hs) {
+ return hs.stream().map(h -> h.asSpreader(Object[].class, h.type().parameterCount())).toArray(MethodHandle[]::new);
+ }
+
+ /**
+ * This method embodies the most generic loop for use by {@link MethodHandles#loop(MethodHandle[][])}. A handle on
+ * it will be transformed into a handle on a concrete loop instantiation by {@link #makeLoop}.
+ *
+ * @param init loop-local variable initializers.
+ * @param step bodies.
+ * @param pred predicates.
+ * @param fini finalizers.
+ * @param varSize number of loop-local variables.
+ * @param nArgs number of arguments passed to the loop.
+ * @param args arguments to the loop invocation.
+ *
+ * @return the result of executing the loop.
+ */
+ static Object looper(MethodHandle[] init, MethodHandle[] step, MethodHandle[] pred, MethodHandle[] fini,
+ int varSize, int nArgs, Object[] args) throws Throwable {
+ Object[] varsAndArgs = new Object[varSize + nArgs];
+ for (int i = 0, v = 0; i < init.length; ++i) {
+ if (init[i].type().returnType() == void.class) {
+ init[i].invoke(args);
+ } else {
+ varsAndArgs[v++] = init[i].invoke(args);
+ }
+ }
+ System.arraycopy(args, 0, varsAndArgs, varSize, nArgs);
+ final int nSteps = step.length;
+ for (; ; ) {
+ for (int i = 0, v = 0; i < nSteps; ++i) {
+ MethodHandle p = pred[i];
+ MethodHandle s = step[i];
+ MethodHandle f = fini[i];
+ if (s.type().returnType() == void.class) {
+ s.invoke(varsAndArgs);
+ } else {
+ varsAndArgs[v++] = s.invoke(varsAndArgs);
+ }
+ if (!(boolean) p.invoke(varsAndArgs)) {
+ return f.invoke(varsAndArgs);
+ }
+ }
+ }
+ }
+
+ /**
+ * This method is bound as the predicate in {@linkplain MethodHandles#countedLoop(MethodHandle, MethodHandle,
+ * MethodHandle) counting loops}.
+ *
+ * @param counter the counter parameter, passed in during loop execution.
+ * @param limit the upper bound of the parameter, statically bound at loop creation time.
+ *
+ * @return whether the counter has reached the limit.
+ */
+ static boolean countedLoopPredicate(int counter, int limit) {
+ return counter <= limit;
+ }
+
+ /**
+ * This method is bound as the step function in {@linkplain MethodHandles#countedLoop(MethodHandle, MethodHandle,
+ * MethodHandle) counting loops} to increment the counter.
+ *
+ * @param counter the loop counter.
+ *
+ * @return the loop counter incremented by 1.
+ */
+ static int countedLoopStep(int counter, int limit) {
+ return counter + 1;
+ }
+
+ /**
+ * This is bound to initialize the loop-local iterator in {@linkplain MethodHandles#iteratedLoop iterating loops}.
+ *
+ * @param it the {@link Iterable} over which the loop iterates.
+ *
+ * @return an {@link Iterator} over the argument's elements.
+ */
+ static Iterator<?> initIterator(Iterable<?> it) {
+ return it.iterator();
+ }
+
+ /**
+ * This method is bound as the predicate in {@linkplain MethodHandles#iteratedLoop iterating loops}.
+ *
+ * @param it the iterator to be checked.
+ *
+ * @return {@code true} iff there are more elements to iterate over.
+ */
+ static boolean iteratePredicate(Iterator<?> it) {
+ return it.hasNext();
+ }
+
+ /**
+ * This method is bound as the step for retrieving the current value from the iterator in {@linkplain
+ * MethodHandles#iteratedLoop iterating loops}.
+ *
+ * @param it the iterator.
+ *
+ * @return the next element from the iterator.
+ */
+ static Object iterateNext(Iterator<?> it) {
+ return it.next();
+ }
+
+ /**
+ * Makes a {@code try-finally} handle that conforms to the type constraints.
+ *
+ * @param target the target to execute in a {@code try-finally} block.
+ * @param cleanup the cleanup to execute in the {@code finally} block.
+ * @param type the result type of the entire construct.
+ * @param argTypes the types of the arguments.
+ *
+ * @return a handle on the constructed {@code try-finally} block.
+ */
+ static MethodHandle makeTryFinally(MethodHandle target, MethodHandle cleanup, Class<?> type, List<Class<?>> argTypes) {
+ MethodHandle tf = getConstantHandle(type == void.class ? MH_tryFinallyVoidExec : MH_tryFinallyExec);
+
+ // Bind the statically known arguments.
+ tf = MethodHandles.insertArguments(tf, 0, target, cleanup);
+
+ // Turn the args array into an argument list.
+ tf = tf.asCollector(Object[].class, argTypes.size());
+
+ // Finally, make try-finally type.
+ MethodType tfType = MethodType.methodType(type, argTypes);
+ tf = tf.asType(tfType);
+
+ return tf;
+ }
+
+ /**
+ * A method that will be bound during construction of a {@code try-finally} handle with non-{@code void} return type
+ * by {@link MethodHandles#tryFinally(MethodHandle, MethodHandle)}.
+ *
+ * @param target the handle to wrap in a {@code try-finally} block. This will be bound.
+ * @param cleanup the handle to run in any case before returning. This will be bound.
+ * @param args the arguments to the call. These will remain as the argument list.
+ *
+ * @return whatever the execution of the {@code target} returned (it may have been modified by the execution of
+ * {@code cleanup}).
+ * @throws Throwable in case anything is thrown by the execution of {@code target}, the {@link Throwable} will be
+ * passed to the {@code cleanup} handle, which may decide to throw any exception it sees fit.
+ */
+ static Object tryFinallyExecutor(MethodHandle target, MethodHandle cleanup, Object[] args) throws Throwable {
+ Throwable t = null;
+ Object r = null;
+ try {
+ r = target.invoke(args);
+ } catch (Throwable thrown) {
+ t = thrown;
+ throw t;
+ } finally {
+ r = cleanup.invoke(t, r, args);
+ }
+ return r;
+ }
+
+ /**
+ * A method that will be bound during construction of a {@code try-finally} handle with {@code void} return type by
+ * {@link MethodHandles#tryFinally(MethodHandle, MethodHandle)}.
+ *
+ * @param target the handle to wrap in a {@code try-finally} block. This will be bound.
+ * @param cleanup the handle to run in any case before returning. This will be bound.
+ * @param args the arguments to the call. These will remain as the argument list.
+ *
+ * @throws Throwable in case anything is thrown by the execution of {@code target}, the {@link Throwable} will be
+ * passed to the {@code cleanup} handle, which may decide to throw any exception it sees fit.
+ */
+ static void tryFinallyVoidExecutor(MethodHandle target, MethodHandle cleanup, Object[] args) throws Throwable {
+ Throwable t = null;
+ try {
+ target.invoke(args);
+ } catch (Throwable thrown) {
+ t = thrown;
+ throw t;
+ } finally {
+ cleanup.invoke(t, args);
+ }
+ }
+
+ // Indexes into constant method handles:
+ static final int
+ MH_cast = 0,
+ MH_selectAlternative = 1,
+ MH_copyAsPrimitiveArray = 2,
+ MH_fillNewTypedArray = 3,
+ MH_fillNewArray = 4,
+ MH_arrayIdentity = 5,
+ MH_looper = 6,
+ MH_countedLoopPred = 7,
+ MH_countedLoopStep = 8,
+ MH_iteratePred = 9,
+ MH_initIterator = 10,
+ MH_iterateNext = 11,
+ MH_tryFinallyExec = 12,
+ MH_tryFinallyVoidExec = 13,
+ MH_LIMIT = 14;
+
+ static MethodHandle getConstantHandle(int idx) {
+ MethodHandle handle = HANDLES[idx];
+ if (handle != null) {
+ return handle;
+ }
+ return setCachedHandle(idx, makeConstantHandle(idx));
+ }
+
+ private static synchronized MethodHandle setCachedHandle(int idx, final MethodHandle method) {
+ // Simulate a CAS, to avoid racy duplication of results.
+ MethodHandle prev = HANDLES[idx];
+ if (prev != null) {
+ return prev;
+ }
+ HANDLES[idx] = method;
+ return method;
+ }
+
+ // Local constant method handles:
+ private static final @Stable MethodHandle[] HANDLES = new MethodHandle[MH_LIMIT];
+
+ private static MethodHandle makeConstantHandle(int idx) {
+ try {
+ switch (idx) {
+ case MH_cast:
+ return IMPL_LOOKUP.findVirtual(Class.class, "cast",
+ MethodType.methodType(Object.class, Object.class));
+ case MH_copyAsPrimitiveArray:
+ return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "copyAsPrimitiveArray",
+ MethodType.methodType(Object.class, Wrapper.class, Object[].class));
+ case MH_arrayIdentity:
+ return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "identity",
+ MethodType.methodType(Object[].class, Object[].class));
+ case MH_fillNewArray:
+ return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "fillNewArray",
+ MethodType.methodType(Object[].class, Integer.class, Object[].class));
+ case MH_fillNewTypedArray:
+ return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "fillNewTypedArray",
+ MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
+ case MH_selectAlternative:
+ return makeIntrinsic(IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative",
+ MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)),
+ Intrinsic.SELECT_ALTERNATIVE);
+ case MH_looper:
+ return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "looper", MethodType.methodType(Object.class,
+ MethodHandle[].class, MethodHandle[].class, MethodHandle[].class, MethodHandle[].class,
+ int.class, int.class, Object[].class));
+ case MH_countedLoopPred:
+ return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "countedLoopPredicate",
+ MethodType.methodType(boolean.class, int.class, int.class));
+ case MH_countedLoopStep:
+ return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "countedLoopStep",
+ MethodType.methodType(int.class, int.class, int.class));
+ case MH_iteratePred:
+ return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "iteratePredicate",
+ MethodType.methodType(boolean.class, Iterator.class));
+ case MH_initIterator:
+ return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "initIterator",
+ MethodType.methodType(Iterator.class, Iterable.class));
+ case MH_iterateNext:
+ return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "iterateNext",
+ MethodType.methodType(Object.class, Iterator.class));
+ case MH_tryFinallyExec:
+ return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "tryFinallyExecutor",
+ MethodType.methodType(Object.class, MethodHandle.class, MethodHandle.class, Object[].class));
+ case MH_tryFinallyVoidExec:
+ return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "tryFinallyVoidExecutor",
+ MethodType.methodType(void.class, MethodHandle.class, MethodHandle.class, Object[].class));
+ }
+ } catch (ReflectiveOperationException ex) {
+ throw newInternalError(ex);
+ }
+ throw newInternalError("Unknown function index: " + idx);
+ }
}
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,10 +26,7 @@
package java.lang.invoke;
import java.lang.reflect.*;
-import java.util.BitSet;
-import java.util.List;
-import java.util.Arrays;
-import java.util.Objects;
+import java.util.*;
import sun.invoke.util.ValueConversions;
import sun.invoke.util.VerifyAccess;
@@ -39,11 +36,13 @@
import sun.reflect.misc.ReflectUtil;
import sun.security.util.SecurityConstants;
import java.lang.invoke.LambdaForm.BasicType;
-import static java.lang.invoke.LambdaForm.BasicType.*;
+
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandleImpl.Intrinsic;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
/**
* This class consists exclusively of static methods that operate on or return
@@ -176,7 +175,7 @@
* equivalent of a particular <em>bytecode behavior</em>.
* (Bytecode behaviors are described in section 5.4.3.5 of the Java Virtual Machine Specification.)
* Here is a summary of the correspondence between these factory methods and
- * the behavior the resulting method handles:
+ * the behavior of the resulting method handles:
* <table border=1 cellpadding=5 summary="lookup method behaviors">
* <tr>
* <th><a name="equiv"></a>lookup expression</th>
@@ -235,6 +234,10 @@
* <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}</td>
* <td>({@code static})?<br>{@code T m(A*);}</td><td>{@code (T) aMethod.invoke(thisOrNull, arg*);}</td>
* </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#findClass lookup.findClass("C")}</td>
+ * <td>{@code class C { ... }}</td><td>{@code C.class;}</td>
+ * </tr>
* </table>
*
* Here, the type {@code C} is the class or interface being searched for a member,
@@ -255,6 +258,10 @@
* The names {@code aMethod}, {@code aField}, and {@code aConstructor} stand
* for reflective objects corresponding to the given members.
* <p>
+ * The bytecode behavior for a {@code findClass} operation is a load of a constant class,
+ * as if by {@code ldc CONSTANT_Class}.
+ * The behavior is represented, not as a method handle, but directly as a {@code Class} constant.
+ * <p>
* In cases where the given member is of variable arity (i.e., a method or constructor)
* the returned method handle will also be of {@linkplain MethodHandle#asVarargsCollector variable arity}.
* In all other cases, the returned method handle will be of fixed arity.
@@ -423,7 +430,7 @@
* and the Core Reflection API
* (as found on {@link java.lang.Class Class}).
* <p>
- * If a security manager is present, member lookups are subject to
+ * If a security manager is present, member and class lookups are subject to
* additional checks.
* From one to three calls are made to the security manager.
* Any of these calls can refuse access by throwing a
@@ -433,6 +440,8 @@
* {@code refc} as the containing class in which the member
* is being sought, and {@code defc} as the class in which the
* member is actually defined.
+ * (If a class or other type is being accessed,
+ * the {@code refc} and {@code defc} values are the class itself.)
* The value {@code lookc} is defined as <em>not present</em>
* if the current lookup object does not have
* <a href="MethodHandles.Lookup.html#privacc">private access</a>.
@@ -444,11 +453,16 @@
* then {@link SecurityManager#checkPackageAccess
* smgr.checkPackageAccess(refcPkg)} is called,
* where {@code refcPkg} is the package of {@code refc}.
- * <li><b>Step 2:</b>
+ * <li><b>Step 2a:</b>
* If the retrieved member is not public and
* {@code lookc} is not present, then
* {@link SecurityManager#checkPermission smgr.checkPermission}
* with {@code RuntimePermission("accessDeclaredMembers")} is called.
+ * <li><b>Step 2b:</b>
+ * If the retrieved class has a {@code null} class loader,
+ * and {@code lookc} is not present, then
+ * {@link SecurityManager#checkPermission smgr.checkPermission}
+ * with {@code RuntimePermission("getClassLoader")} is called.
* <li><b>Step 3:</b>
* If the retrieved member is not public,
* and if {@code lookc} is not present,
@@ -458,9 +472,9 @@
* where {@code defcPkg} is the package of {@code defc}.
* </ul>
* Security checks are performed after other access checks have passed.
- * Therefore, the above rules presuppose a member that is public,
+ * Therefore, the above rules presuppose a member or class that is public,
* or else that is being accessed from a lookup class that has
- * rights to access the member.
+ * rights to access the member or class.
*
* <h1><a name="callsens"></a>Caller sensitive methods</h1>
* A small number of Java methods have a special property called caller sensitivity.
@@ -922,6 +936,49 @@
}
/**
+ * Looks up a class by name from the lookup context defined by this {@code Lookup} object. The static
+ * initializer of the class is not run.
+ *
+ * @param targetName the fully qualified name of the class to be looked up.
+ * @return the requested class.
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws LinkageError if the linkage fails
+ * @throws ClassNotFoundException if the class does not exist.
+ * @throws IllegalAccessException if the class is not accessible, using the allowed access
+ * modes.
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @since 9
+ */
+ public Class<?> findClass(String targetName) throws ClassNotFoundException, IllegalAccessException {
+ Class<?> targetClass = Class.forName(targetName, false, lookupClass.getClassLoader());
+ return accessClass(targetClass);
+ }
+
+ /**
+ * Determines if a class can be accessed from the lookup context defined by this {@code Lookup} object. The
+ * static initializer of the class is not run.
+ *
+ * @param targetClass the class to be access-checked
+ *
+ * @return the class that has been access-checked
+ *
+ * @throws IllegalAccessException if the class is not accessible from the lookup class, using the allowed access
+ * modes.
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @since 9
+ */
+ public Class<?> accessClass(Class<?> targetClass) throws IllegalAccessException {
+ if (!VerifyAccess.isClassAccessible(targetClass, lookupClass, allowedModes)) {
+ throw new MemberName(targetClass).makeAccessException("access violation", this);
+ }
+ checkSecurityManager(targetClass, null);
+ return targetClass;
+ }
+
+ /**
* Produces an early-bound method handle for a virtual method.
* It will bypass checks for overriding methods on the receiver,
* <a href="MethodHandles.Lookup.html#equiv">as if called</a> from an {@code invokespecial}
@@ -995,7 +1052,7 @@
*/
public MethodHandle findSpecial(Class<?> refc, String name, MethodType type,
Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
- checkSpecialCaller(specialCaller);
+ checkSpecialCaller(specialCaller, refc);
Lookup specialLookup = this.in(specialCaller);
MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type);
return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, findBoundCallerClass(method));
@@ -1224,7 +1281,7 @@
* @throws NullPointerException if any argument is null
*/
public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException {
- checkSpecialCaller(specialCaller);
+ checkSpecialCaller(specialCaller, null);
Lookup specialLookup = this.in(specialCaller);
MemberName method = new MemberName(m, true);
assert(method.isMethod());
@@ -1444,7 +1501,15 @@
ReflectUtil.checkPackageAccess(refc);
}
- // Step 2:
+ if (m == null) { // findClass or accessClass
+ // Step 2b:
+ if (!fullPowerLookup) {
+ smgr.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
+ }
+ return;
+ }
+
+ // Step 2a:
if (m.isPublic()) return;
if (!fullPowerLookup) {
smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
@@ -1557,11 +1622,13 @@
private static final boolean ALLOW_NESTMATE_ACCESS = false;
- private void checkSpecialCaller(Class<?> specialCaller) throws IllegalAccessException {
+ private void checkSpecialCaller(Class<?> specialCaller, Class<?> refc) throws IllegalAccessException {
int allowedModes = this.allowedModes;
if (allowedModes == TRUSTED) return;
if (!hasPrivateAccess()
|| (specialCaller != lookupClass()
+ // ensure non-abstract methods in superinterfaces can be special-invoked
+ && !(refc != null && refc.isInterface() && refc.isAssignableFrom(specialCaller))
&& !(ALLOW_NESTMATE_ACCESS &&
VerifyAccess.isSamePackageMember(specialCaller, lookupClass()))))
throw new MemberName(specialCaller).
@@ -1888,7 +1955,7 @@
MethodHandle spreadInvoker(MethodType type, int leadingArgCount) {
if (leadingArgCount < 0 || leadingArgCount > type.parameterCount())
throw newIllegalArgumentException("bad argument count", leadingArgCount);
- type = type.asSpreaderType(Object[].class, type.parameterCount() - leadingArgCount);
+ type = type.asSpreaderType(Object[].class, leadingArgCount, type.parameterCount() - leadingArgCount);
return type.invokers().spreadInvoker(leadingArgCount);
}
@@ -2924,19 +2991,7 @@
*/
public static
MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
- int foldPos = 0;
- MethodType targetType = target.type();
- MethodType combinerType = combiner.type();
- Class<?> rtype = foldArgumentChecks(foldPos, targetType, combinerType);
- BoundMethodHandle result = target.rebind();
- boolean dropResult = (rtype == void.class);
- // Note: This may cache too many distinct LFs. Consider backing off to varargs code.
- LambdaForm lform = result.editor().foldArgumentsForm(1 + foldPos, dropResult, combinerType.basicType());
- MethodType newType = targetType;
- if (!dropResult)
- newType = newType.dropParameterTypes(foldPos, foldPos + 1);
- result = result.copyWithExtendL(newType, lform, combiner);
- return result;
+ return foldArguments(target, 0, combiner);
}
private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) {
@@ -2949,7 +3004,7 @@
.equals(targetType.parameterList().subList(afterInsertPos,
afterInsertPos + foldArgs))))
ok = false;
- if (ok && foldVals != 0 && combinerType.returnType() != targetType.parameterType(0))
+ if (ok && foldVals != 0 && combinerType.returnType() != targetType.parameterType(foldPos))
ok = false;
if (!ok)
throw misMatchedTypes("target and combiner types", targetType, combinerType);
@@ -3011,7 +3066,7 @@
return MethodHandleImpl.makeGuardWithTest(test, target, fallback);
}
- static RuntimeException misMatchedTypes(String what, MethodType t1, MethodType t2) {
+ static <T> RuntimeException misMatchedTypes(String what, T t1, T t2) {
return newIllegalArgumentException(what + " must match: " + t1 + " != " + t2);
}
@@ -3057,6 +3112,7 @@
* the given exception type, or if the method handle types do
* not match in their return types and their
* corresponding parameters
+ * @see MethodHandles#tryFinally(MethodHandle, MethodHandle)
*/
public static
MethodHandle catchException(MethodHandle target,
@@ -3100,4 +3156,913 @@
throw new ClassCastException(exType.getName());
return MethodHandleImpl.throwException(MethodType.methodType(returnType, exType));
}
+
+ /**
+ * Constructs a method handle representing a loop with several loop variables that are updated and checked upon each
+ * iteration. Upon termination of the loop due to one of the predicates, a corresponding finalizer is run and
+ * delivers the loop's result, which is the return value of the resulting handle.
+ * <p>
+ * Intuitively, every loop is formed by one or more "clauses", each specifying a local iteration value and/or a loop
+ * exit. Each iteration of the loop executes each clause in order. A clause can optionally update its iteration
+ * variable; it can also optionally perform a test and conditional loop exit. In order to express this logic in
+ * terms of method handles, each clause will determine four actions:<ul>
+ * <li>Before the loop executes, the initialization of an iteration variable or loop invariant local.
+ * <li>When a clause executes, an update step for the iteration variable.
+ * <li>When a clause executes, a predicate execution to test for loop exit.
+ * <li>If a clause causes a loop exit, a finalizer execution to compute the loop's return value.
+ * </ul>
+ * <p>
+ * Some of these clause parts may be omitted according to certain rules, and useful default behavior is provided in
+ * this case. See below for a detailed description.
+ * <p>
+ * Each clause function, with the exception of clause initializers, is able to observe the entire loop state,
+ * because it will be passed <em>all</em> current iteration variable values, as well as all incoming loop
+ * parameters. Most clause functions will not need all of this information, but they will be formally connected as
+ * if by {@link #dropArguments}.
+ * <p>
+ * Given a set of clauses, there is a number of checks and adjustments performed to connect all the parts of the
+ * loop. They are spelled out in detail in the steps below. In these steps, every occurrence of the word "must"
+ * corresponds to a place where {@link IllegalArgumentException} may be thrown if the required constraint is not met
+ * by the inputs to the loop combinator. The term "effectively identical", applied to parameter type lists, means
+ * that they must be identical, or else one list must be a proper prefix of the other.
+ * <p>
+ * <em>Step 0: Determine clause structure.</em><ol type="a">
+ * <li>The clause array (of type {@code MethodHandle[][]} must be non-{@code null} and contain at least one element.
+ * <li>The clause array may not contain {@code null}s or sub-arrays longer than four elements.
+ * <li>Clauses shorter than four elements are treated as if they were padded by {@code null} elements to length
+ * four. Padding takes place by appending elements to the array.
+ * <li>Clauses with all {@code null}s are disregarded.
+ * <li>Each clause is treated as a four-tuple of functions, called "init", "step", "pred", and "fini".
+ * </ol>
+ * <p>
+ * <em>Step 1A: Determine iteration variables.</em><ol type="a">
+ * <li>Examine init and step function return types, pairwise, to determine each clause's iteration variable type.
+ * <li>If both functions are omitted, use {@code void}; else if one is omitted, use the other's return type; else
+ * use the common return type (they must be identical).
+ * <li>Form the list of return types (in clause order), omitting all occurrences of {@code void}.
+ * <li>This list of types is called the "common prefix".
+ * </ol>
+ * <p>
+ * <em>Step 1B: Determine loop parameters.</em><ol type="a">
+ * <li>Examine init function parameter lists.
+ * <li>Omitted init functions are deemed to have {@code null} parameter lists.
+ * <li>All init function parameter lists must be effectively identical.
+ * <li>The longest parameter list (which is necessarily unique) is called the "common suffix".
+ * </ol>
+ * <p>
+ * <em>Step 1C: Determine loop return type.</em><ol type="a">
+ * <li>Examine fini function return types, disregarding omitted fini functions.
+ * <li>If there are no fini functions, use {@code void} as the loop return type.
+ * <li>Otherwise, use the common return type of the fini functions; they must all be identical.
+ * </ol>
+ * <p>
+ * <em>Step 1D: Check other types.</em><ol type="a">
+ * <li>There must be at least one non-omitted pred function.
+ * <li>Every non-omitted pred function must have a {@code boolean} return type.
+ * </ol>
+ * <p>
+ * (Implementation Note: Steps 1A, 1B, 1C, 1D are logically independent of each other, and may be performed in any
+ * order.)
+ * <p>
+ * <em>Step 2: Determine parameter lists.</em><ol type="a">
+ * <li>The parameter list for the resulting loop handle will be the "common suffix".
+ * <li>The parameter list for init functions will be adjusted to the "common suffix". (Note that their parameter
+ * lists are already effectively identical to the common suffix.)
+ * <li>The parameter list for non-init (step, pred, and fini) functions will be adjusted to the common prefix
+ * followed by the common suffix, called the "common parameter sequence".
+ * <li>Every non-init, non-omitted function parameter list must be effectively identical to the common parameter
+ * sequence.
+ * </ol>
+ * <p>
+ * <em>Step 3: Fill in omitted functions.</em><ol type="a">
+ * <li>If an init function is omitted, use a {@linkplain #constant constant function} of the appropriate
+ * {@code null}/zero/{@code false}/{@code void} type. (For this purpose, a constant {@code void} is simply a
+ * function which does nothing and returns {@code void}; it can be obtained from another constant function by
+ * {@linkplain MethodHandle#asType type conversion}.)
+ * <li>If a step function is omitted, use an {@linkplain #identity identity function} of the clause's iteration
+ * variable type; insert dropped argument parameters before the identity function parameter for the non-{@code void}
+ * iteration variables of preceding clauses. (This will turn the loop variable into a local loop invariant.)
+ * <li>If a pred function is omitted, the corresponding fini function must also be omitted.
+ * <li>If a pred function is omitted, use a constant {@code true} function. (This will keep the loop going, as far
+ * as this clause is concerned.)
+ * <li>If a fini function is omitted, use a constant {@code null}/zero/{@code false}/{@code void} function of the
+ * loop return type.
+ * </ol>
+ * <p>
+ * <em>Step 4: Fill in missing parameter types.</em><ol type="a">
+ * <li>At this point, every init function parameter list is effectively identical to the common suffix, but some
+ * lists may be shorter. For every init function with a short parameter list, pad out the end of the list by
+ * {@linkplain #dropArguments dropping arguments}.
+ * <li>At this point, every non-init function parameter list is effectively identical to the common parameter
+ * sequence, but some lists may be shorter. For every non-init function with a short parameter list, pad out the end
+ * of the list by {@linkplain #dropArguments dropping arguments}.
+ * </ol>
+ * <p>
+ * <em>Final observations.</em><ol type="a">
+ * <li>After these steps, all clauses have been adjusted by supplying omitted functions and arguments.
+ * <li>All init functions have a common parameter type list, which the final loop handle will also have.
+ * <li>All fini functions have a common return type, which the final loop handle will also have.
+ * <li>All non-init functions have a common parameter type list, which is the common parameter sequence, of
+ * (non-{@code void}) iteration variables followed by loop parameters.
+ * <li>Each pair of init and step functions agrees in their return types.
+ * <li>Each non-init function will be able to observe the current values of all iteration variables, by means of the
+ * common prefix.
+ * </ol>
+ * <p>
+ * <em>Loop execution.</em><ol type="a">
+ * <li>When the loop is called, the loop input values are saved in locals, to be passed (as the common suffix) to
+ * every clause function. These locals are loop invariant.
+ * <li>Each init function is executed in clause order (passing the common suffix) and the non-{@code void} values
+ * are saved (as the common prefix) into locals. These locals are loop varying (unless their steps are identity
+ * functions, as noted above).
+ * <li>All function executions (except init functions) will be passed the common parameter sequence, consisting of
+ * the non-{@code void} iteration values (in clause order) and then the loop inputs (in argument order).
+ * <li>The step and pred functions are then executed, in clause order (step before pred), until a pred function
+ * returns {@code false}.
+ * <li>The non-{@code void} result from a step function call is used to update the corresponding loop variable. The
+ * updated value is immediately visible to all subsequent function calls.
+ * <li>If a pred function returns {@code false}, the corresponding fini function is called, and the resulting value
+ * is returned from the loop as a whole.
+ * </ol>
+ * <p>
+ * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the types / values
+ * of loop variables; {@code A}/{@code a}, those of arguments passed to the resulting loop; and {@code R}, the
+ * result types of finalizers as well as of the resulting loop.
+ * <blockquote><pre>{@code
+ * V... init...(A...);
+ * boolean pred...(V..., A...);
+ * V... step...(V..., A...);
+ * R fini...(V..., A...);
+ * R loop(A... a) {
+ * V... v... = init...(a...);
+ * for (;;) {
+ * for ((v, p, s, f) in (v..., pred..., step..., fini...)) {
+ * v = s(v..., a...);
+ * if (!p(v..., a...)) {
+ * return f(v..., a...);
+ * }
+ * }
+ * }
+ * }
+ * }</pre></blockquote>
+ * <p>
+ * @apiNote Example:
+ * <blockquote><pre>{@code
+ * // iterative implementation of the factorial function as a loop handle
+ * static int one(int k) { return 1; }
+ * int inc(int i, int acc, int k) { return i + 1; }
+ * int mult(int i, int acc, int k) { return i * acc; }
+ * boolean pred(int i, int acc, int k) { return i < k; }
+ * int fin(int i, int acc, int k) { return acc; }
+ * // assume MH_one, MH_inc, MH_mult, MH_pred, and MH_fin are handles to the above methods
+ * // null initializer for counter, should initialize to 0
+ * MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc};
+ * MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin};
+ * MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);
+ * assertEquals(120, loop.invoke(5));
+ * }</pre></blockquote>
+ *
+ * @param clauses an array of arrays (4-tuples) of {@link MethodHandle}s adhering to the rules described above.
+ *
+ * @return a method handle embodying the looping behavior as defined by the arguments.
+ *
+ * @throws IllegalArgumentException in case any of the constraints described above is violated.
+ *
+ * @see MethodHandles#whileLoop(MethodHandle, MethodHandle, MethodHandle)
+ * @see MethodHandles#doWhileLoop(MethodHandle, MethodHandle, MethodHandle)
+ * @see MethodHandles#countedLoop(MethodHandle, MethodHandle, MethodHandle)
+ * @see MethodHandles#iteratedLoop(MethodHandle, MethodHandle, MethodHandle)
+ * @since 9
+ */
+ public static MethodHandle loop(MethodHandle[]... clauses) {
+ // Step 0: determine clause structure.
+ checkLoop0(clauses);
+
+ List<MethodHandle> init = new ArrayList<>();
+ List<MethodHandle> step = new ArrayList<>();
+ List<MethodHandle> pred = new ArrayList<>();
+ List<MethodHandle> fini = new ArrayList<>();
+
+ Stream.of(clauses).filter(c -> Stream.of(c).anyMatch(Objects::nonNull)).forEach(clause -> {
+ init.add(clause[0]); // all clauses have at least length 1
+ step.add(clause.length <= 1 ? null : clause[1]);
+ pred.add(clause.length <= 2 ? null : clause[2]);
+ fini.add(clause.length <= 3 ? null : clause[3]);
+ });
+
+ assert Stream.of(init, step, pred, fini).map(List::size).distinct().count() == 1;
+ final int nclauses = init.size();
+
+ // Step 1A: determine iteration variables.
+ final List<Class<?>> iterationVariableTypes = new ArrayList<>();
+ for (int i = 0; i < nclauses; ++i) {
+ MethodHandle in = init.get(i);
+ MethodHandle st = step.get(i);
+ if (in == null && st == null) {
+ iterationVariableTypes.add(void.class);
+ } else if (in != null && st != null) {
+ checkLoop1a(i, in, st);
+ iterationVariableTypes.add(in.type().returnType());
+ } else {
+ iterationVariableTypes.add(in == null ? st.type().returnType() : in.type().returnType());
+ }
+ }
+ final List<Class<?>> commonPrefix = iterationVariableTypes.stream().filter(t -> t != void.class).
+ collect(Collectors.toList());
+
+ // Step 1B: determine loop parameters.
+ final List<Class<?>> empty = new ArrayList<>();
+ final List<Class<?>> commonSuffix = init.stream().filter(Objects::nonNull).map(MethodHandle::type).
+ map(MethodType::parameterList).reduce((p, q) -> p.size() >= q.size() ? p : q).orElse(empty);
+ checkLoop1b(init, commonSuffix);
+
+ // Step 1C: determine loop return type.
+ // Step 1D: check other types.
+ final Class<?> loopReturnType = fini.stream().filter(Objects::nonNull).map(MethodHandle::type).
+ map(MethodType::returnType).findFirst().orElse(void.class);
+ checkLoop1cd(pred, fini, loopReturnType);
+
+ // Step 2: determine parameter lists.
+ final List<Class<?>> commonParameterSequence = new ArrayList<>(commonPrefix);
+ commonParameterSequence.addAll(commonSuffix);
+ checkLoop2(step, pred, fini, commonParameterSequence);
+
+ // Step 3: fill in omitted functions.
+ for (int i = 0; i < nclauses; ++i) {
+ Class<?> t = iterationVariableTypes.get(i);
+ if (init.get(i) == null) {
+ init.set(i, zeroHandle(t));
+ }
+ if (step.get(i) == null) {
+ step.set(i, dropArguments(t == void.class ? zeroHandle(t) : identity(t), 0, commonPrefix.subList(0, i)));
+ }
+ if (pred.get(i) == null) {
+ pred.set(i, constant(boolean.class, true));
+ }
+ if (fini.get(i) == null) {
+ fini.set(i, zeroHandle(t));
+ }
+ }
+
+ // Step 4: fill in missing parameter types.
+ List<MethodHandle> finit = fillParameterTypes(init, commonSuffix);
+ List<MethodHandle> fstep = fillParameterTypes(step, commonParameterSequence);
+ List<MethodHandle> fpred = fillParameterTypes(pred, commonParameterSequence);
+ List<MethodHandle> ffini = fillParameterTypes(fini, commonParameterSequence);
+
+ assert finit.stream().map(MethodHandle::type).map(MethodType::parameterList).
+ allMatch(pl -> pl.equals(commonSuffix));
+ assert Stream.of(fstep, fpred, ffini).flatMap(List::stream).map(MethodHandle::type).map(MethodType::parameterList).
+ allMatch(pl -> pl.equals(commonParameterSequence));
+
+ return MethodHandleImpl.makeLoop(loopReturnType, commonSuffix, commonPrefix, finit, fstep, fpred, ffini);
+ }
+
+ private static List<MethodHandle> fillParameterTypes(List<MethodHandle> hs, final List<Class<?>> targetParams) {
+ return hs.stream().map(h -> {
+ int pc = h.type().parameterCount();
+ int tpsize = targetParams.size();
+ return pc < tpsize ? dropArguments(h, pc, targetParams.subList(pc, tpsize)) : h;
+ }).collect(Collectors.toList());
+ }
+
+ /**
+ * Constructs a {@code while} loop from an initializer, a body, and a predicate. This is a convenience wrapper for
+ * the {@linkplain #loop(MethodHandle[][]) generic loop combinator}.
+ * <p>
+ * The loop handle's result type is the same as the sole loop variable's, i.e., the result type of {@code init}.
+ * The parameter type list of {@code init} also determines that of the resulting handle. The {@code pred} handle
+ * must have an additional leading parameter of the same type as {@code init}'s result, and so must the {@code
+ * body}. These constraints follow directly from those described for the {@linkplain MethodHandles#loop(MethodHandle[][])
+ * generic loop combinator}.
+ * <p>
+ * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
+ * the sole loop variable as well as the result type of the loop; and {@code A}/{@code a}, that of the argument
+ * passed to the loop.
+ * <blockquote><pre>{@code
+ * V init(A);
+ * boolean pred(V, A);
+ * V body(V, A);
+ * V whileLoop(A a) {
+ * V v = init(a);
+ * while (pred(v, a)) {
+ * v = body(v, a);
+ * }
+ * return v;
+ * }
+ * }</pre></blockquote>
+ * <p>
+ * @apiNote Example:
+ * <blockquote><pre>{@code
+ * // implement the zip function for lists as a loop handle
+ * List<String> initZip(Iterator<String> a, Iterator<String> b) { return new ArrayList<>(); }
+ * boolean zipPred(List<String> zip, Iterator<String> a, Iterator<String> b) { return a.hasNext() && b.hasNext(); }
+ * List<String> zipStep(List<String> zip, Iterator<String> a, Iterator<String> b) {
+ * zip.add(a.next());
+ * zip.add(b.next());
+ * return zip;
+ * }
+ * // assume MH_initZip, MH_zipPred, and MH_zipStep are handles to the above methods
+ * MethodHandle loop = MethodHandles.doWhileLoop(MH_initZip, MH_zipPred, MH_zipStep);
+ * List<String> a = Arrays.asList("a", "b", "c", "d");
+ * List<String> b = Arrays.asList("e", "f", "g", "h");
+ * List<String> zipped = Arrays.asList("a", "e", "b", "f", "c", "g", "d", "h");
+ * assertEquals(zipped, (List<String>) loop.invoke(a.iterator(), b.iterator()));
+ * }</pre></blockquote>
+ *
+ * <p>
+ * @implSpec The implementation of this method is equivalent to:
+ * <blockquote><pre>{@code
+ * MethodHandle whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body) {
+ * MethodHandle[]
+ * checkExit = {null, null, pred, identity(init.type().returnType())},
+ * varBody = {init, body};
+ * return loop(checkExit, varBody);
+ * }
+ * }</pre></blockquote>
+ *
+ * @param init initializer: it should provide the initial value of the loop variable. This controls the loop's
+ * result type. Passing {@code null} or a {@code void} init function will make the loop's result type
+ * {@code void}.
+ * @param pred condition for the loop, which may not be {@code null}.
+ * @param body body of the loop, which may not be {@code null}.
+ *
+ * @return the value of the loop variable as the loop terminates.
+ * @throws IllegalArgumentException if any argument has a type inconsistent with the loop structure
+ *
+ * @see MethodHandles#loop(MethodHandle[][])
+ * @since 9
+ */
+ public static MethodHandle whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body) {
+ MethodHandle fin = init == null ? zeroHandle(void.class) : identity(init.type().returnType());
+ MethodHandle[] checkExit = {null, null, pred, fin};
+ MethodHandle[] varBody = {init, body};
+ return loop(checkExit, varBody);
+ }
+
+ /**
+ * Constructs a {@code do-while} loop from an initializer, a body, and a predicate. This is a convenience wrapper
+ * for the {@linkplain MethodHandles#loop(MethodHandle[][]) generic loop combinator}.
+ * <p>
+ * The loop handle's result type is the same as the sole loop variable's, i.e., the result type of {@code init}.
+ * The parameter type list of {@code init} also determines that of the resulting handle. The {@code pred} handle
+ * must have an additional leading parameter of the same type as {@code init}'s result, and so must the {@code
+ * body}. These constraints follow directly from those described for the {@linkplain MethodHandles#loop(MethodHandle[][])
+ * generic loop combinator}.
+ * <p>
+ * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
+ * the sole loop variable as well as the result type of the loop; and {@code A}/{@code a}, that of the argument
+ * passed to the loop.
+ * <blockquote><pre>{@code
+ * V init(A);
+ * boolean pred(V, A);
+ * V body(V, A);
+ * V doWhileLoop(A a) {
+ * V v = init(a);
+ * do {
+ * v = body(v, a);
+ * } while (pred(v, a));
+ * return v;
+ * }
+ * }</pre></blockquote>
+ * <p>
+ * @apiNote Example:
+ * <blockquote><pre>{@code
+ * // int i = 0; while (i < limit) { ++i; } return i; => limit
+ * int zero(int limit) { return 0; }
+ * int step(int i, int limit) { return i + 1; }
+ * boolean pred(int i, int limit) { return i < limit; }
+ * // assume MH_zero, MH_step, and MH_pred are handles to the above methods
+ * MethodHandle loop = MethodHandles.doWhileLoop(MH_zero, MH_step, MH_pred);
+ * assertEquals(23, loop.invoke(23));
+ * }</pre></blockquote>
+ *
+ * <p>
+ * @implSpec The implementation of this method is equivalent to:
+ * <blockquote><pre>{@code
+ * MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred) {
+ * MethodHandle[] clause = { init, body, pred, identity(init.type().returnType()) };
+ * return loop(clause);
+ * }
+ * }</pre></blockquote>
+ *
+ *
+ * @param init initializer: it should provide the initial value of the loop variable. This controls the loop's
+ * result type. Passing {@code null} or a {@code void} init function will make the loop's result type
+ * {@code void}.
+ * @param pred condition for the loop, which may not be {@code null}.
+ * @param body body of the loop, which may not be {@code null}.
+ *
+ * @return the value of the loop variable as the loop terminates.
+ * @throws IllegalArgumentException if any argument has a type inconsistent with the loop structure
+ *
+ * @see MethodHandles#loop(MethodHandle[][])
+ * @since 9
+ */
+ public static MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred) {
+ MethodHandle fin = init == null ? zeroHandle(void.class) : identity(init.type().returnType());
+ MethodHandle[] clause = {init, body, pred, fin};
+ return loop(clause);
+ }
+
+ /**
+ * Constructs a loop that runs a given number of iterations. The loop counter is an {@code int} initialized from the
+ * {@code iterations} handle evaluation result. The counter is passed to the {@code body} function, so that must
+ * accept an initial {@code int} argument. The result of the loop execution is the final value of the additional
+ * local state. This is a convenience wrapper for the {@linkplain MethodHandles#loop(MethodHandle[][]) generic loop
+ * combinator}.
+ * <p>
+ * The result type and parameter type list of {@code init} determine those of the resulting handle. The {@code
+ * iterations} handle must accept the same parameter types as {@code init} but return an {@code int}. The {@code
+ * body} handle must accept the same parameter types as well, preceded by an {@code int} parameter for the counter,
+ * and a parameter of the same type as {@code init}'s result. These constraints follow directly from those described
+ * for the {@linkplain MethodHandles#loop(MethodHandle[][]) generic loop combinator}.
+ * <p>
+ * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
+ * the sole loop variable as well as the result type of the loop; and {@code A}/{@code a}, that of the argument
+ * passed to the loop.
+ * <blockquote><pre>{@code
+ * int iterations(A);
+ * V init(A);
+ * V body(int, V, A);
+ * V countedLoop(A a) {
+ * int end = iterations(a);
+ * V v = init(a);
+ * for (int i = 0; i < end; ++i) {
+ * v = body(i, v, a);
+ * }
+ * return v;
+ * }
+ * }</pre></blockquote>
+ * <p>
+ * @apiNote Example:
+ * <blockquote><pre>{@code
+ * // String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s;
+ * // => a variation on a well known theme
+ * String start(String arg) { return arg; }
+ * String step(int counter, String v, String arg) { return "na " + v; }
+ * // assume MH_start and MH_step are handles to the two methods above
+ * MethodHandle loop = MethodHandles.countedLoop(13, MH_start, MH_step);
+ * assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("Lambdaman!"));
+ * }</pre></blockquote>
+ *
+ * <p>
+ * @implSpec The implementation of this method is equivalent to:
+ * <blockquote><pre>{@code
+ * MethodHandle countedLoop(MethodHandle iterations, MethodHandle init, MethodHandle body) {
+ * return countedLoop(null, iterations, init, body); // null => constant zero
+ * }
+ * }</pre></blockquote>
+ *
+ * @param iterations a handle to return the number of iterations this loop should run.
+ * @param init initializer for additional loop state. This determines the loop's result type.
+ * Passing {@code null} or a {@code void} init function will make the loop's result type
+ * {@code void}.
+ * @param body the body of the loop, which must not be {@code null}.
+ * It must accept an initial {@code int} parameter (for the counter), and then any
+ * additional loop-local variable plus loop parameters.
+ *
+ * @return a method handle representing the loop.
+ * @throws IllegalArgumentException if any argument has a type inconsistent with the loop structure
+ *
+ * @since 9
+ */
+ public static MethodHandle countedLoop(MethodHandle iterations, MethodHandle init, MethodHandle body) {
+ return countedLoop(null, iterations, init, body);
+ }
+
+ /**
+ * Constructs a loop that counts over a range of numbers. The loop counter is an {@code int} that will be
+ * initialized to the {@code int} value returned from the evaluation of the {@code start} handle and run to the
+ * value returned from {@code end} (exclusively) with a step width of 1. The counter value is passed to the {@code
+ * body} function in each iteration; it has to accept an initial {@code int} parameter
+ * for that. The result of the loop execution is the final value of the additional local state
+ * obtained by running {@code init}.
+ * This is a
+ * convenience wrapper for the {@linkplain MethodHandles#loop(MethodHandle[][]) generic loop combinator}.
+ * <p>
+ * The constraints for the {@code init} and {@code body} handles are the same as for {@link
+ * #countedLoop(MethodHandle, MethodHandle, MethodHandle)}. Additionally, the {@code start} and {@code end} handles
+ * must return an {@code int} and accept the same parameters as {@code init}.
+ * <p>
+ * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
+ * the sole loop variable as well as the result type of the loop; and {@code A}/{@code a}, that of the argument
+ * passed to the loop.
+ * <blockquote><pre>{@code
+ * int start(A);
+ * int end(A);
+ * V init(A);
+ * V body(int, V, A);
+ * V countedLoop(A a) {
+ * int s = start(a);
+ * int e = end(a);
+ * V v = init(a);
+ * for (int i = s; i < e; ++i) {
+ * v = body(i, v, a);
+ * }
+ * return v;
+ * }
+ * }</pre></blockquote>
+ *
+ * <p>
+ * @implSpec The implementation of this method is equivalent to:
+ * <blockquote><pre>{@code
+ * MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
+ * MethodHandle returnVar = dropArguments(identity(init.type().returnType()), 0, int.class, int.class);
+ * // assume MH_increment and MH_lessThan are handles to x+1 and x<y of type int
+ * MethodHandle[]
+ * indexVar = {start, MH_increment}, // i = start; i = i+1
+ * loopLimit = {end, null, MH_lessThan, returnVar }, // i<end
+ * bodyClause = {init, dropArguments(body, 1, int.class)}; // v = body(i, v);
+ * return loop(indexVar, loopLimit, bodyClause);
+ * }
+ * }</pre></blockquote>
+ *
+ * @param start a handle to return the start value of the loop counter.
+ * If it is {@code null}, a constant zero is assumed.
+ * @param end a non-{@code null} handle to return the end value of the loop counter (the loop will run to {@code end-1}).
+ * @param init initializer for additional loop state. This determines the loop's result type.
+ * Passing {@code null} or a {@code void} init function will make the loop's result type
+ * {@code void}.
+ * @param body the body of the loop, which must not be {@code null}.
+ * It must accept an initial {@code int} parameter (for the counter), and then any
+ * additional loop-local variable plus loop parameters.
+ *
+ * @return a method handle representing the loop.
+ * @throws IllegalArgumentException if any argument has a type inconsistent with the loop structure
+ *
+ * @since 9
+ */
+ public static MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
+ MethodHandle returnVar = dropArguments(init == null ? zeroHandle(void.class) : identity(init.type().returnType()),
+ 0, int.class, int.class);
+ MethodHandle[] indexVar = {start, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopStep)};
+ MethodHandle[] loopLimit = {end, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopPred), returnVar};
+ MethodHandle[] bodyClause = {init, dropArguments(body, 1, int.class)};
+ return loop(indexVar, loopLimit, bodyClause);
+ }
+
+ /**
+ * Constructs a loop that ranges over the elements produced by an {@code Iterator<T>}.
+ * The iterator will be produced by the evaluation of the {@code iterator} handle.
+ * If this handle is passed as {@code null} the method {@link Iterable#iterator} will be used instead,
+ * and will be applied to a leading argument of the loop handle.
+ * Each value produced by the iterator is passed to the {@code body}, which must accept an initial {@code T} parameter.
+ * The result of the loop execution is the final value of the additional local state
+ * obtained by running {@code init}.
+ * <p>
+ * This is a convenience wrapper for the
+ * {@linkplain MethodHandles#loop(MethodHandle[][]) generic loop combinator}, and the constraints imposed on the {@code body}
+ * handle follow directly from those described for the latter.
+ * <p>
+ * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
+ * the loop variable as well as the result type of the loop; {@code T}/{@code t}, that of the elements of the
+ * structure the loop iterates over, and {@code A}/{@code a}, that of the argument passed to the loop.
+ * <blockquote><pre>{@code
+ * Iterator<T> iterator(A); // defaults to Iterable::iterator
+ * V init(A);
+ * V body(T,V,A);
+ * V iteratedLoop(A a) {
+ * Iterator<T> it = iterator(a);
+ * V v = init(a);
+ * for (T t : it) {
+ * v = body(t, v, a);
+ * }
+ * return v;
+ * }
+ * }</pre></blockquote>
+ * <p>
+ * The type {@code T} may be either a primitive or reference.
+ * Since type {@code Iterator<T>} is erased in the method handle representation to the raw type
+ * {@code Iterator}, the {@code iteratedLoop} combinator adjusts the leading argument type for {@code body}
+ * to {@code Object} as if by the {@link MethodHandle#asType asType} conversion method.
+ * Therefore, if an iterator of the wrong type appears as the loop is executed,
+ * runtime exceptions may occur as the result of dynamic conversions performed by {@code asType}.
+ * <p>
+ * @apiNote Example:
+ * <blockquote><pre>{@code
+ * // reverse a list
+ * List<String> reverseStep(String e, List<String> r) {
+ * r.add(0, e);
+ * return r;
+ * }
+ * List<String> newArrayList() { return new ArrayList<>(); }
+ * // assume MH_reverseStep, MH_newArrayList are handles to the above methods
+ * MethodHandle loop = MethodHandles.iteratedLoop(null, MH_newArrayList, MH_reverseStep);
+ * List<String> list = Arrays.asList("a", "b", "c", "d", "e");
+ * List<String> reversedList = Arrays.asList("e", "d", "c", "b", "a");
+ * assertEquals(reversedList, (List<String>) loop.invoke(list));
+ * }</pre></blockquote>
+ * <p>
+ * @implSpec The implementation of this method is equivalent to:
+ * <blockquote><pre>{@code
+ * MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) {
+ * // assume MH_next and MH_hasNext are handles to methods of Iterator
+ * Class<?> itype = iterator.type().returnType();
+ * Class<?> ttype = body.type().parameterType(0);
+ * MethodHandle returnVar = dropArguments(identity(init.type().returnType()), 0, itype);
+ * MethodHandle nextVal = MH_next.asType(MH_next.type().changeReturnType(ttype));
+ * MethodHandle[]
+ * iterVar = {iterator, null, MH_hasNext, returnVar}, // it = iterator(); while (it.hasNext)
+ * bodyClause = {init, filterArgument(body, 0, nextVal)}; // v = body(t, v, a);
+ * return loop(iterVar, bodyClause);
+ * }
+ * }</pre></blockquote>
+ *
+ * @param iterator a handle to return the iterator to start the loop.
+ * Passing {@code null} will make the loop call {@link Iterable#iterator()} on the first
+ * incoming value.
+ * @param init initializer for additional loop state. This determines the loop's result type.
+ * Passing {@code null} or a {@code void} init function will make the loop's result type
+ * {@code void}.
+ * @param body the body of the loop, which must not be {@code null}.
+ * It must accept an initial {@code T} parameter (for the iterated values), and then any
+ * additional loop-local variable plus loop parameters.
+ *
+ * @return a method handle embodying the iteration loop functionality.
+ * @throws IllegalArgumentException if any argument has a type inconsistent with the loop structure
+ *
+ * @since 9
+ */
+ public static MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) {
+ checkIteratedLoop(body);
+
+ MethodHandle initit = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_initIterator);
+ MethodHandle initIterator = iterator == null ?
+ initit.asType(initit.type().changeParameterType(0, body.type().parameterType(init == null ? 1 : 2))) :
+ iterator;
+ Class<?> itype = initIterator.type().returnType();
+ Class<?> ttype = body.type().parameterType(0);
+
+ MethodHandle returnVar =
+ dropArguments(init == null ? zeroHandle(void.class) : identity(init.type().returnType()), 0, itype);
+ MethodHandle initnx = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iterateNext);
+ MethodHandle nextVal = initnx.asType(initnx.type().changeReturnType(ttype));
+
+ MethodHandle[] iterVar = {initIterator, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iteratePred), returnVar};
+ MethodHandle[] bodyClause = {init, filterArgument(body, 0, nextVal)};
+
+ return loop(iterVar, bodyClause);
+ }
+
+ /**
+ * Makes a method handle that adapts a {@code target} method handle by wrapping it in a {@code try-finally} block.
+ * Another method handle, {@code cleanup}, represents the functionality of the {@code finally} block. Any exception
+ * thrown during the execution of the {@code target} handle will be passed to the {@code cleanup} handle. The
+ * exception will be rethrown, unless {@code cleanup} handle throws an exception first. The
+ * value returned from the {@code cleanup} handle's execution will be the result of the execution of the
+ * {@code try-finally} handle.
+ * <p>
+ * The {@code cleanup} handle will be passed one or two additional leading arguments.
+ * The first is the exception thrown during the
+ * execution of the {@code target} handle, or {@code null} if no exception was thrown.
+ * The second is the result of the execution of the {@code target} handle, or, if it throws an exception,
+ * a {@code null}, zero, or {@code false} value of the required type is supplied as a placeholder.
+ * The second argument is not present if the {@code target} handle has a {@code void} return type.
+ * (Note that, except for argument type conversions, combinators represent {@code void} values in parameter lists
+ * by omitting the corresponding paradoxical arguments, not by inserting {@code null} or zero values.)
+ * <p>
+ * The {@code target} and {@code cleanup} handles' return types must be the same. Their parameter type lists also
+ * must be the same, but the {@code cleanup} handle must accept one or two more leading parameters:<ul>
+ * <li>a {@code Throwable}, which will carry the exception thrown by the {@code target} handle (if any); and
+ * <li>a parameter of the same type as the return type of both {@code target} and {@code cleanup}, which will carry
+ * the result from the execution of the {@code target} handle.
+ * This parameter is not present if the {@code target} returns {@code void}.
+ * </ul>
+ * <p>
+ * The pseudocode for the resulting adapter looks as follows. In the code, {@code V} represents the result type of
+ * the {@code try/finally} construct; {@code A}/{@code a}, the types and values of arguments to the resulting
+ * handle consumed by the cleanup; and {@code B}/{@code b}, those of arguments to the resulting handle discarded by
+ * the cleanup.
+ * <blockquote><pre>{@code
+ * V target(A..., B...);
+ * V cleanup(Throwable, V, A...);
+ * V adapter(A... a, B... b) {
+ * V result = (zero value for V);
+ * Throwable throwable = null;
+ * try {
+ * result = target(a..., b...);
+ * } catch (Throwable t) {
+ * throwable = t;
+ * throw t;
+ * } finally {
+ * result = cleanup(throwable, result, a...);
+ * }
+ * return result;
+ * }
+ * }</pre></blockquote>
+ * <p>
+ * Note that the saved arguments ({@code a...} in the pseudocode) cannot
+ * be modified by execution of the target, and so are passed unchanged
+ * from the caller to the cleanup, if it is invoked.
+ * <p>
+ * The target and cleanup must return the same type, even if the cleanup
+ * always throws.
+ * To create such a throwing cleanup, compose the cleanup logic
+ * with {@link #throwException throwException},
+ * in order to create a method handle of the correct return type.
+ * <p>
+ * Note that {@code tryFinally} never converts exceptions into normal returns.
+ * In rare cases where exceptions must be converted in that way, first wrap
+ * the target with {@link #catchException(MethodHandle, Class, MethodHandle)}
+ * to capture an outgoing exception, and then wrap with {@code tryFinally}.
+ *
+ * @param target the handle whose execution is to be wrapped in a {@code try} block.
+ * @param cleanup the handle that is invoked in the finally block.
+ *
+ * @return a method handle embodying the {@code try-finally} block composed of the two arguments.
+ * @throws NullPointerException if any argument is null
+ * @throws IllegalArgumentException if {@code cleanup} does not accept
+ * the required leading arguments, or if the method handle types do
+ * not match in their return types and their
+ * corresponding trailing parameters
+ *
+ * @see MethodHandles#catchException(MethodHandle, Class, MethodHandle)
+ * @since 9
+ */
+ public static MethodHandle tryFinally(MethodHandle target, MethodHandle cleanup) {
+ List<Class<?>> targetParamTypes = target.type().parameterList();
+ List<Class<?>> cleanupParamTypes = cleanup.type().parameterList();
+ Class<?> rtype = target.type().returnType();
+
+ checkTryFinally(target, cleanup);
+
+ // Match parameter lists: if the cleanup has a shorter parameter list than the target, add ignored arguments.
+ int tpSize = targetParamTypes.size();
+ int cpPrefixLength = rtype == void.class ? 1 : 2;
+ int cpSize = cleanupParamTypes.size();
+ MethodHandle aCleanup = cpSize - cpPrefixLength < tpSize ?
+ dropArguments(cleanup, cpSize, targetParamTypes.subList(tpSize - (cpSize - cpPrefixLength), tpSize)) :
+ cleanup;
+
+ MethodHandle aTarget = target.asSpreader(Object[].class, target.type().parameterCount());
+ aCleanup = aCleanup.asSpreader(Object[].class, tpSize);
+
+ return MethodHandleImpl.makeTryFinally(aTarget, aCleanup, rtype, targetParamTypes);
+ }
+
+ /**
+ * Adapts a target method handle by pre-processing some of its arguments, starting at a given position, and then
+ * calling the target with the result of the pre-processing, inserted into the original sequence of arguments just
+ * before the folded arguments.
+ * <p>
+ * This method is closely related to {@link #foldArguments(MethodHandle, MethodHandle)}, but allows to control the
+ * position in the parameter list at which folding takes place. The argument controlling this, {@code pos}, is a
+ * zero-based index. The aforementioned method {@link #foldArguments(MethodHandle, MethodHandle)} assumes position
+ * 0.
+ * <p>
+ * @apiNote Example:
+ * <blockquote><pre>{@code
+ import static java.lang.invoke.MethodHandles.*;
+ import static java.lang.invoke.MethodType.*;
+ ...
+ MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,
+ "println", methodType(void.class, String.class))
+ .bindTo(System.out);
+ MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+ assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
+ MethodHandle catTrace = foldArguments(cat, 1, trace);
+ // also prints "jum":
+ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
+ * }</pre></blockquote>
+ * <p> Here is pseudocode for the resulting adapter:
+ * <blockquote><pre>{@code
+ * // there are N arguments in A...
+ * T target(Z..., V, A[N]..., B...);
+ * V combiner(A...);
+ * T adapter(Z... z, A... a, B... b) {
+ * V v = combiner(a...);
+ * return target(z..., v, a..., b...);
+ * }
+ * // and if the combiner has a void return:
+ * T target2(Z..., A[N]..., B...);
+ * void combiner2(A...);
+ * T adapter2(Z... z, A... a, B... b) {
+ * combiner2(a...);
+ * return target2(z..., a..., b...);
+ * }
+ * }</pre></blockquote>
+ *
+ * @param target the method handle to invoke after arguments are combined
+ * @param pos the position at which to start folding and at which to insert the folding result; if this is {@code
+ * 0}, the effect is the same as for {@link #foldArguments(MethodHandle, MethodHandle)}.
+ * @param combiner method handle to call initially on the incoming arguments
+ * @return method handle which incorporates the specified argument folding logic
+ * @throws NullPointerException if either argument is null
+ * @throws IllegalArgumentException if {@code combiner}'s return type
+ * is non-void and not the same as the argument type at position {@code pos} of
+ * the target signature, or if the {@code N} argument types at position {@code pos}
+ * of the target signature
+ * (skipping one matching the {@code combiner}'s return type)
+ * are not identical with the argument types of {@code combiner}
+ *
+ * @see #foldArguments(MethodHandle, MethodHandle)
+ * @since 9
+ */
+ public static MethodHandle foldArguments(MethodHandle target, int pos, MethodHandle combiner) {
+ MethodType targetType = target.type();
+ MethodType combinerType = combiner.type();
+ Class<?> rtype = foldArgumentChecks(pos, targetType, combinerType);
+ BoundMethodHandle result = target.rebind();
+ boolean dropResult = rtype == void.class;
+ LambdaForm lform = result.editor().foldArgumentsForm(1 + pos, dropResult, combinerType.basicType());
+ MethodType newType = targetType;
+ if (!dropResult) {
+ newType = newType.dropParameterTypes(pos, pos + 1);
+ }
+ result = result.copyWithExtendL(newType, lform, combiner);
+ return result;
+ }
+
+ /**
+ * Wrap creation of a proper zero handle for a given type.
+ *
+ * @param type the type.
+ *
+ * @return a zero value for the given type.
+ */
+ static MethodHandle zeroHandle(Class<?> type) {
+ return type.isPrimitive() ? zero(Wrapper.forPrimitiveType(type), type) : zero(Wrapper.OBJECT, type);
+ }
+
+ private static void checkLoop0(MethodHandle[][] clauses) {
+ if (clauses == null || clauses.length == 0) {
+ throw newIllegalArgumentException("null or no clauses passed");
+ }
+ if (Stream.of(clauses).anyMatch(Objects::isNull)) {
+ throw newIllegalArgumentException("null clauses are not allowed");
+ }
+ if (Stream.of(clauses).anyMatch(c -> c.length > 4)) {
+ throw newIllegalArgumentException("All loop clauses must be represented as MethodHandle arrays with at most 4 elements.");
+ }
+ }
+
+ private static void checkLoop1a(int i, MethodHandle in, MethodHandle st) {
+ if (in.type().returnType() != st.type().returnType()) {
+ throw misMatchedTypes("clause " + i + ": init and step return types", in.type().returnType(),
+ st.type().returnType());
+ }
+ }
+
+ private static void checkLoop1b(List<MethodHandle> init, List<Class<?>> commonSuffix) {
+ if (init.stream().filter(Objects::nonNull).map(MethodHandle::type).map(MethodType::parameterList).
+ anyMatch(pl -> !pl.equals(commonSuffix.subList(0, pl.size())))) {
+ throw newIllegalArgumentException("found non-effectively identical init parameter type lists: " + init +
+ " (common suffix: " + commonSuffix + ")");
+ }
+ }
+
+ private static void checkLoop1cd(List<MethodHandle> pred, List<MethodHandle> fini, Class<?> loopReturnType) {
+ if (fini.stream().filter(Objects::nonNull).map(MethodHandle::type).map(MethodType::returnType).
+ anyMatch(t -> t != loopReturnType)) {
+ throw newIllegalArgumentException("found non-identical finalizer return types: " + fini + " (return type: " +
+ loopReturnType + ")");
+ }
+
+ if (!pred.stream().filter(Objects::nonNull).findFirst().isPresent()) {
+ throw newIllegalArgumentException("no predicate found", pred);
+ }
+ if (pred.stream().filter(Objects::nonNull).map(MethodHandle::type).map(MethodType::returnType).
+ anyMatch(t -> t != boolean.class)) {
+ throw newIllegalArgumentException("predicates must have boolean return type", pred);
+ }
+ }
+
+ private static void checkLoop2(List<MethodHandle> step, List<MethodHandle> pred, List<MethodHandle> fini, List<Class<?>> commonParameterSequence) {
+ if (Stream.of(step, pred, fini).flatMap(List::stream).filter(Objects::nonNull).map(MethodHandle::type).
+ map(MethodType::parameterList).anyMatch(pl -> !pl.equals(commonParameterSequence.subList(0, pl.size())))) {
+ throw newIllegalArgumentException("found non-effectively identical parameter type lists:\nstep: " + step +
+ "\npred: " + pred + "\nfini: " + fini + " (common parameter sequence: " + commonParameterSequence + ")");
+ }
+ }
+
+ private static void checkIteratedLoop(MethodHandle body) {
+ if (null == body) {
+ throw newIllegalArgumentException("iterated loop body must not be null");
+ }
+ }
+
+ private static void checkTryFinally(MethodHandle target, MethodHandle cleanup) {
+ Class<?> rtype = target.type().returnType();
+ if (rtype != cleanup.type().returnType()) {
+ throw misMatchedTypes("target and return types", cleanup.type().returnType(), rtype);
+ }
+ List<Class<?>> cleanupParamTypes = cleanup.type().parameterList();
+ if (!Throwable.class.isAssignableFrom(cleanupParamTypes.get(0))) {
+ throw misMatchedTypes("cleanup first argument and Throwable", cleanup.type(), Throwable.class);
+ }
+ if (rtype != void.class && cleanupParamTypes.get(1) != rtype) {
+ throw misMatchedTypes("cleanup second argument and target return type", cleanup.type(), rtype);
+ }
+ // The cleanup parameter list (minus the leading Throwable and result parameters) must be a sublist of the
+ // target parameter list.
+ int cleanupArgIndex = rtype == void.class ? 1 : 2;
+ if (!cleanupParamTypes.subList(cleanupArgIndex, cleanupParamTypes.size()).
+ equals(target.type().parameterList().subList(0, cleanupParamTypes.size() - cleanupArgIndex))) {
+ throw misMatchedTypes("cleanup parameters after (Throwable,result) and target parameter list prefix",
+ cleanup.type(), target.type());
+ }
+ }
+
}
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java Wed Jul 05 21:02:29 2017 +0200
@@ -469,12 +469,13 @@
/** Replace the last arrayLength parameter types with the component type of arrayType.
* @param arrayType any array type
+ * @param pos position at which to spread
* @param arrayLength the number of parameter types to change
* @return the resulting type
*/
- /*non-public*/ MethodType asSpreaderType(Class<?> arrayType, int arrayLength) {
+ /*non-public*/ MethodType asSpreaderType(Class<?> arrayType, int pos, int arrayLength) {
assert(parameterCount() >= arrayLength);
- int spreadPos = ptypes.length - arrayLength;
+ int spreadPos = pos;
if (arrayLength == 0) return this; // nothing to change
if (arrayType == Object[].class) {
if (isGeneric()) return this; // nothing to change
@@ -489,10 +490,10 @@
}
Class<?> elemType = arrayType.getComponentType();
assert(elemType != null);
- for (int i = spreadPos; i < ptypes.length; i++) {
+ for (int i = spreadPos; i < spreadPos + arrayLength; i++) {
if (ptypes[i] != elemType) {
Class<?>[] fixedPtypes = ptypes.clone();
- Arrays.fill(fixedPtypes, i, ptypes.length, elemType);
+ Arrays.fill(fixedPtypes, i, spreadPos + arrayLength, elemType);
return methodType(rtype, fixedPtypes);
}
}
@@ -512,12 +513,14 @@
/** Delete the last parameter type and replace it with arrayLength copies of the component type of arrayType.
* @param arrayType any array type
+ * @param pos position at which to insert parameters
* @param arrayLength the number of parameter types to insert
* @return the resulting type
*/
- /*non-public*/ MethodType asCollectorType(Class<?> arrayType, int arrayLength) {
+ /*non-public*/ MethodType asCollectorType(Class<?> arrayType, int pos, int arrayLength) {
assert(parameterCount() >= 1);
- assert(lastParameterType().isAssignableFrom(arrayType));
+ assert(pos < ptypes.length);
+ assert(ptypes[pos].isAssignableFrom(arrayType));
MethodType res;
if (arrayType == Object[].class) {
res = genericMethodType(arrayLength);
@@ -532,7 +535,11 @@
if (ptypes.length == 1) {
return res;
} else {
- return res.insertParameterTypes(0, parameterList().subList(0, ptypes.length-1));
+ // insert after (if need be), then before
+ if (pos < parameterList().size() - 1) {
+ res = res.insertParameterTypes(arrayLength, parameterList().subList(pos + 1, parameterList().size()));
+ }
+ return res.insertParameterTypes(0, parameterList().subList(0, pos));
}
}
--- a/jdk/src/java.base/share/classes/java/time/Clock.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/time/Clock.java Wed Jul 05 21:02:29 2017 +0200
@@ -65,7 +65,7 @@
import java.io.ObjectInputStream;
import static java.time.LocalTime.NANOS_PER_MINUTE;
import static java.time.LocalTime.NANOS_PER_SECOND;
-
+import static java.time.LocalTime.NANOS_PER_MILLI;
import java.io.Serializable;
import java.util.Objects;
import java.util.TimeZone;
@@ -182,7 +182,7 @@
}
/**
- * Obtains a clock that returns the current instant using best available
+ * Obtains a clock that returns the current instant using the best available
* system clock.
* <p>
* This clock is based on the best available system clock.
@@ -206,8 +206,32 @@
//-------------------------------------------------------------------------
/**
+ * Obtains a clock that returns the current instant ticking in whole milliseconds
+ * using the best available system clock.
+ * <p>
+ * This clock will always have the nano-of-second field truncated to milliseconds.
+ * This ensures that the visible time ticks in whole milliseconds.
+ * The underlying clock is the best available system clock, equivalent to
+ * using {@link #system(ZoneId)}.
+ * <p>
+ * Implementations may use a caching strategy for performance reasons.
+ * As such, it is possible that the start of the millisecond observed via this
+ * clock will be later than that observed directly via the underlying clock.
+ * <p>
+ * The returned implementation is immutable, thread-safe and {@code Serializable}.
+ * It is equivalent to {@code tick(system(zone), Duration.ofMillis(1))}.
+ *
+ * @param zone the time-zone to use to convert the instant to date-time, not null
+ * @return a clock that ticks in whole milliseconds using the specified zone, not null
+ */
+ public static Clock tickMillis(ZoneId zone) {
+ return new TickClock(system(zone), NANOS_PER_MILLI);
+ }
+
+ //-------------------------------------------------------------------------
+ /**
* Obtains a clock that returns the current instant ticking in whole seconds
- * using best available system clock.
+ * using the best available system clock.
* <p>
* This clock will always have the nano-of-second field set to zero.
* This ensures that the visible time ticks in whole seconds.
@@ -230,7 +254,7 @@
/**
* Obtains a clock that returns the current instant ticking in whole minutes
- * using best available system clock.
+ * using the best available system clock.
* <p>
* This clock will always have the nano-of-second and second-of-minute fields set to zero.
* This ensures that the visible time ticks in whole minutes.
--- a/jdk/src/java.base/share/classes/java/time/Duration.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/time/Duration.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -359,8 +359,8 @@
* there must be at least one section after the "T".
* The number part of each section must consist of one or more ASCII digits.
* The number may be prefixed by the ASCII negative or positive symbol.
- * The number of days, hours and minutes must parse to an {@code long}.
- * The number of seconds must parse to an {@code long} with optional fraction.
+ * The number of days, hours and minutes must parse to a {@code long}.
+ * The number of seconds must parse to a {@code long} with optional fraction.
* The decimal point may be either a dot or a comma.
* The fractional part may have from zero to 9 digits.
* <p>
@@ -374,9 +374,9 @@
* "PT10H" -- parses as "10 hours" (where an hour is 3600 seconds)
* "P2D" -- parses as "2 days" (where a day is 24 hours or 86400 seconds)
* "P2DT3H4M" -- parses as "2 days, 3 hours and 4 minutes"
- * "P-6H3M" -- parses as "-6 hours and +3 minutes"
- * "-P6H3M" -- parses as "-6 hours and -3 minutes"
- * "-P-6H+3M" -- parses as "+6 hours and -3 minutes"
+ * "PT-6H3M" -- parses as "-6 hours and +3 minutes"
+ * "-PT6H3M" -- parses as "-6 hours and -3 minutes"
+ * "-PT-6H+3M" -- parses as "+6 hours and -3 minutes"
* </pre>
*
* @param text the text to parse, not null
@@ -402,7 +402,8 @@
long hoursAsSecs = parseNumber(text, hourStart, hourEnd, SECONDS_PER_HOUR, "hours");
long minsAsSecs = parseNumber(text, minuteStart, minuteEnd, SECONDS_PER_MINUTE, "minutes");
long seconds = parseNumber(text, secondStart, secondEnd, 1, "seconds");
- int nanos = parseFraction(text, fractionStart, fractionEnd, seconds < 0 ? -1 : 1);
+ boolean negativeSecs = secondStart >= 0 && text.charAt(secondStart) == '-';
+ int nanos = parseFraction(text, fractionStart, fractionEnd, negativeSecs ? -1 : 1);
try {
return create(negate, daysAsSecs, hoursAsSecs, minsAsSecs, seconds, nanos);
} catch (ArithmeticException ex) {
--- a/jdk/src/java.base/share/classes/java/time/LocalDate.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/time/LocalDate.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -81,7 +81,7 @@
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.time.chrono.ChronoLocalDate;
-import java.time.chrono.Era;
+import java.time.chrono.IsoEra;
import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
@@ -220,12 +220,8 @@
*/
public static LocalDate now(Clock clock) {
Objects.requireNonNull(clock, "clock");
- // inline to avoid creating object and Instant checks
final Instant now = clock.instant(); // called once
- ZoneOffset offset = clock.getZone().getRules().getOffset(now);
- long epochSec = now.getEpochSecond() + offset.getTotalSeconds(); // overflow caught later
- long epochDay = Math.floorDiv(epochSec, SECONDS_PER_DAY);
- return LocalDate.ofEpochDay(epochDay);
+ return ofInstant(now, clock.getZone());
}
//-----------------------------------------------------------------------
@@ -300,6 +296,30 @@
//-----------------------------------------------------------------------
/**
+ * Obtains an instance of {@code LocalDate} from an {@code Instant} and zone ID.
+ * <p>
+ * This creates a local date based on the specified instant.
+ * First, the offset from UTC/Greenwich is obtained using the zone ID and instant,
+ * which is simple as there is only one valid offset for each instant.
+ * Then, the instant and offset are used to calculate the local date.
+ *
+ * @param instant the instant to create the date from, not null
+ * @param zone the time-zone, which may be an offset, not null
+ * @return the local date, not null
+ * @throws DateTimeException if the result exceeds the supported range
+ */
+ public static LocalDate ofInstant(Instant instant, ZoneId zone) {
+ Objects.requireNonNull(instant, "instant");
+ Objects.requireNonNull(zone, "zone");
+ ZoneRules rules = zone.getRules();
+ ZoneOffset offset = rules.getOffset(instant);
+ long localSecond = instant.getEpochSecond() + offset.getTotalSeconds();
+ long localEpochDay = Math.floorDiv(localSecond, SECONDS_PER_DAY);
+ return ofEpochDay(localEpochDay);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
* Obtains an instance of {@code LocalDate} from the epoch day count.
* <p>
* This returns a {@code LocalDate} with the specified epoch-day.
@@ -712,15 +732,12 @@
* Users of this class should typically ignore this method as it exists primarily
* to fulfill the {@link ChronoLocalDate} contract where it is necessary to support
* the Japanese calendar system.
- * <p>
- * The returned era will be a singleton capable of being compared with the constants
- * in {@link IsoChronology} using the {@code ==} operator.
*
- * @return the {@code IsoChronology} era constant applicable at this date, not null
+ * @return the IsoEra applicable at this date, not null
*/
@Override // override for Javadoc
- public Era getEra() {
- return ChronoLocalDate.super.getEra();
+ public IsoEra getEra() {
+ return (getYear() >= 1 ? IsoEra.CE : IsoEra.BCE);
}
/**
--- a/jdk/src/java.base/share/classes/java/time/LocalTime.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/time/LocalTime.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -190,9 +190,13 @@
*/
static final long MICROS_PER_DAY = SECONDS_PER_DAY * 1000_000L;
/**
+ * Nanos per millisecond.
+ */
+ static final long NANOS_PER_MILLI = 1000_000L;
+ /**
* Nanos per second.
*/
- static final long NANOS_PER_SECOND = 1000_000_000L;
+ static final long NANOS_PER_SECOND = 1000_000_000L;
/**
* Nanos per minute.
*/
@@ -272,12 +276,8 @@
*/
public static LocalTime now(Clock clock) {
Objects.requireNonNull(clock, "clock");
- // inline OffsetTime factory to avoid creating object and InstantProvider checks
final Instant now = clock.instant(); // called once
- ZoneOffset offset = clock.getZone().getRules().getOffset(now);
- long localSecond = now.getEpochSecond() + offset.getTotalSeconds(); // overflow caught later
- int secsOfDay = (int) Math.floorMod(localSecond, SECONDS_PER_DAY);
- return ofNanoOfDay(secsOfDay * NANOS_PER_SECOND + now.getNano());
+ return ofInstant(now, clock.getZone());
}
//-----------------------------------------------------------------------
@@ -343,6 +343,27 @@
return create(hour, minute, second, nanoOfSecond);
}
+ /**
+ * Obtains an instance of {@code LocalTime} from an {@code Instant} and zone ID.
+ * <p>
+ * This creates a local time based on the specified instant.
+ * First, the offset from UTC/Greenwich is obtained using the zone ID and instant,
+ * which is simple as there is only one valid offset for each instant.
+ * Then, the instant and offset are used to calculate the local time.
+ *
+ * @param instant the instant to create the time from, not null
+ * @param zone the time-zone, which may be an offset, not null
+ * @return the local time, not null
+ */
+ public static LocalTime ofInstant(Instant instant, ZoneId zone) {
+ Objects.requireNonNull(instant, "instant");
+ Objects.requireNonNull(zone, "zone");
+ ZoneOffset offset = zone.getRules().getOffset(instant);
+ long localSecond = instant.getEpochSecond() + offset.getTotalSeconds();
+ int secsOfDay = (int) Math.floorMod(localSecond, SECONDS_PER_DAY);
+ return ofNanoOfDay(secsOfDay * NANOS_PER_SECOND + instant.getNano());
+ }
+
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code LocalTime} from a second-of-day value.
--- a/jdk/src/java.base/share/classes/java/util/Arrays.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/util/Arrays.java Wed Jul 05 21:02:29 2017 +0200
@@ -3305,6 +3305,103 @@
return true;
}
+ /**
+ * Returns {@code true} if the two specified arrays of Objects are
+ * <i>equal</i> to one another.
+ *
+ * <p>Two arrays are considered equal if both arrays contain the same number
+ * of elements, and all corresponding pairs of elements in the two arrays
+ * are equal. In other words, the two arrays are equal if they contain the
+ * same elements in the same order. Also, two array references are
+ * considered equal if both are {@code null}.
+ *
+ * <p>Two objects {@code e1} and {@code e2} are considered <i>equal</i> if,
+ * given the specified comparator, {@code cmp.compare(e1, e2) == 0}.
+ *
+ * @param a one array to be tested for equality
+ * @param a2 the other array to be tested for equality
+ * @param cmp the comparator to compare array elements
+ * @param <T> the type of array elements
+ * @return {@code true} if the two arrays are equal
+ * @throws NullPointerException if the comparator is {@code null}
+ * @since 9
+ */
+ public static <T> boolean equals(T[] a, T[] a2, Comparator<? super T> cmp) {
+ Objects.requireNonNull(cmp);
+ if (a==a2)
+ return true;
+ if (a==null || a2==null)
+ return false;
+
+ int length = a.length;
+ if (a2.length != length)
+ return false;
+
+ for (int i=0; i<length; i++) {
+ if (cmp.compare(a[i], a2[i]) != 0)
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns true if the two specified arrays of Objects, over the specified
+ * ranges, are <i>equal</i> to one another.
+ *
+ * <p>Two arrays are considered equal if the number of elements covered by
+ * each range is the same, and all corresponding pairs of elements over the
+ * specified ranges in the two arrays are equal. In other words, two arrays
+ * are equal if they contain, over the specified ranges, the same elements
+ * in the same order.
+ *
+ * <p>Two objects {@code e1} and {@code e2} are considered <i>equal</i> if,
+ * given the specified comparator, {@code cmp.compare(e1, e2) == 0}.
+ *
+ * @param a the first array to be tested for equality
+ * @param aFromIndex the index (inclusive) of the first element in the
+ * first array to be tested
+ * @param aToIndex the index (exclusive) of the last element in the
+ * first array to be tested
+ * @param b the second array to be tested fro equality
+ * @param bFromIndex the index (inclusive) of the first element in the
+ * second array to be tested
+ * @param bToIndex the index (exclusive) of the last element in the
+ * second array to be tested
+ * @param cmp the comparator to compare array elements
+ * @param <T> the type of array elements
+ * @return {@code true} if the two arrays, over the specified ranges, are
+ * equal
+ * @throws IllegalArgumentException
+ * if {@code aFromIndex > aToIndex} or
+ * if {@code bFromIndex > bToIndex}
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code aFromIndex < 0 or aToIndex > a.length} or
+ * if {@code bFromIndex < 0 or bToIndex > b.length}
+ * @throws NullPointerException
+ * if either array or the comparator is {@code null}
+ * @since 9
+ */
+ public static <T> boolean equals(T[] a, int aFromIndex, int aToIndex,
+ T[] b, int bFromIndex, int bToIndex,
+ Comparator<? super T> cmp) {
+ Objects.requireNonNull(cmp);
+ rangeCheck(a.length, aFromIndex, aToIndex);
+ rangeCheck(b.length, bFromIndex, bToIndex);
+
+ int aLength = aToIndex - aFromIndex;
+ int bLength = bToIndex - bFromIndex;
+ if (aLength != bLength)
+ return false;
+
+ for (int i = 0; i < aLength; i++) {
+ if (cmp.compare(a[aFromIndex++], b[bFromIndex++]) != 0)
+ return false;
+ }
+
+ return true;
+ }
+
// Filling
/**
@@ -8744,9 +8841,7 @@
* <pre>{@code
* pl >= 0 &&
* pl < Math.min(a.length, b.length) &&
- * IntStream.range(0, pl).
- * map(i -> cmp.compare(a[i], b[i])).
- * allMatch(c -> c == 0) &&
+ * Arrays.equals(a, 0, pl, b, 0, pl, cmp)
* cmp.compare(a[pl], b[pl]) != 0
* }</pre>
* Note that a common prefix length of {@code 0} indicates that the first
@@ -8756,9 +8851,9 @@
* prefix if the following expression is true:
* <pre>{@code
* a.length != b.length &&
- * IntStream.range(0, Math.min(a.length, b.length)).
- * map(i -> cmp.compare(a[i], b[i])).
- * allMatch(c -> c == 0) &&
+ * Arrays.equals(a, 0, Math.min(a.length, b.length),
+ * b, 0, Math.min(a.length, b.length),
+ * cmp)
* }</pre>
*
* @param a the first array to be tested for a mismatch
@@ -8815,9 +8910,7 @@
* <pre>{@code
* pl >= 0 &&
* pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
- * IntStream.range(0, pl).
- * map(i -> cmp.compare(a[aFromIndex + i], b[bFromIndex + i])).
- * allMatch(c -> c == 0) &&
+ * Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl, cmp) &&
* cmp.compare(a[aFromIndex + pl], b[bFromIndex + pl]) != 0
* }</pre>
* Note that a common prefix length of {@code 0} indicates that the first
@@ -8829,9 +8922,9 @@
* if the following expression is true:
* <pre>{@code
* (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
- * IntStream.range(0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex)).
- * map(i -> cmp.compare(a[aFromIndex + i], b[bFromIndex + i])).
- * allMatch(c -> c == 0)
+ * Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+ * b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+ * cmp)
* }</pre>
*
* @param a the first array to be tested for a mismatch
--- a/jdk/src/java.base/share/classes/java/util/Objects.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/util/Objects.java Wed Jul 05 21:02:29 2017 +0200
@@ -352,15 +352,16 @@
* @param b the second out of bound value
* @param oobe the exception mapping function that when applied with out of
* bounds arguments returns a runtime exception. If {@code null}
- * then, it's as if an exception mapping function was supplied that
+ * then, it is as if an exception mapping function was supplied that
* returns {@link IndexOutOfBoundsException} for any given arguments.
* @return the runtime exception
*/
private static RuntimeException outOfBounds(
int a, int b, BiFunction<Integer, Integer, ? extends RuntimeException> oobe) {
- return oobe == null
- ? new IndexOutOfBoundsException(a, b)
- : oobe.apply(a, b);
+ RuntimeException e = oobe == null
+ ? null : oobe.apply(a, b);
+ return e == null
+ ? new IndexOutOfBoundsException(a, b) : e;
}
/**
@@ -408,8 +409,10 @@
* @param length the upper-bound (exclusive) of the range
* @param oobe the exception mapping function that when applied with out
* of bounds arguments returns a runtime exception. If {@code null}
- * then, it's as if an exception mapping function was supplied that
- * returns {@link IndexOutOfBoundsException} for any given arguments.
+ * or returns {@code null} then, it is as if an exception mapping
+ * function was supplied that returns
+ * {@link IndexOutOfBoundsException} for any given arguments.
+ * Exceptions thrown by the function are relayed to the caller.
* @return {@code index} if it is within bounds of the range
* @throws T if the {@code index} is out of bounds, then a runtime exception
* is thrown that is the result of applying the out of bounds
@@ -484,8 +487,10 @@
* @param length the upper-bound (exclusive) the range
* @param oobe the exception mapping function that when applied with out
* of bounds arguments returns a runtime exception. If {@code null}
- * then, it's as if an exception mapping function was supplied that
- * returns {@link IndexOutOfBoundsException} for any given arguments.
+ * or returns {@code null} then, it is as if an exception mapping
+ * function was supplied that returns
+ * {@link IndexOutOfBoundsException} for any given arguments.
+ * Exceptions thrown by the function are relayed to the caller.
* @return {@code fromIndex} if the sub-range within bounds of the range
* @throws T if the sub-range is out of bounds, then a runtime exception is
* thrown that is the result of applying the out of bounds arguments
@@ -553,8 +558,10 @@
* @param length the upper-bound (exclusive) of the range
* @param oobe the exception mapping function that when applied with out
* of bounds arguments returns a runtime exception. If {@code null}
- * then, it's as if an exception mapping function was supplied that
- * returns {@link IndexOutOfBoundsException} for any given arguments.
+ * or returns {@code null} then, it is as if an exception mapping
+ * function was supplied that returns
+ * {@link IndexOutOfBoundsException} for any given arguments.
+ * Exceptions thrown by the function are relayed to the caller.
* @return {@code fromIndex} if the sub-range within bounds of the range
* @throws T if the sub-range is out of bounds, then a runtime exception is
* thrown that is the result of applying the out of bounds arguments
--- a/jdk/src/java.base/share/classes/java/util/TreeMap.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/util/TreeMap.java Wed Jul 05 21:02:29 2017 +0200
@@ -2581,19 +2581,17 @@
}
/**
- * Find the level down to which to assign all nodes BLACK. This is the
- * last `full' level of the complete binary tree produced by
- * buildTree. The remaining nodes are colored RED. (This makes a `nice'
- * set of color assignments wrt future insertions.) This level number is
+ * Finds the level down to which to assign all nodes BLACK. This is the
+ * last `full' level of the complete binary tree produced by buildTree.
+ * The remaining nodes are colored RED. (This makes a `nice' set of
+ * color assignments wrt future insertions.) This level number is
* computed by finding the number of splits needed to reach the zeroeth
- * node. (The answer is ~lg(N), but in any case must be computed by same
- * quick O(lg(N)) loop.)
+ * node.
+ *
+ * @param size the (non-negative) number of keys in the tree to be built
*/
- private static int computeRedLevel(int sz) {
- int level = 0;
- for (int m = sz - 1; m >= 0; m = m / 2 - 1)
- level++;
- return level;
+ private static int computeRedLevel(int size) {
+ return 31 - Integer.numberOfLeadingZeros(size + 1);
}
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/logger/AbstractLoggerWrapper.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.logger;
+
+import java.util.ResourceBundle;
+import java.util.function.Supplier;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import sun.util.logging.PlatformLogger;
+
+/**
+ * An implementation of {@link System.Logger System.Logger}
+ * that redirects all calls to a wrapped instance of {@link
+ * System.Logger System.Logger}
+ *
+ * @param <L> Type of the wrapped Logger: {@code Logger} or
+ * an extension of that interface.
+ *
+ */
+abstract class AbstractLoggerWrapper<L extends Logger>
+ implements Logger, PlatformLogger.Bridge, PlatformLogger.ConfigurableBridge {
+
+ AbstractLoggerWrapper() { }
+
+ abstract L wrapped();
+
+ abstract PlatformLogger.Bridge platformProxy();
+
+ L getWrapped() {
+ return wrapped();
+ }
+
+ @Override
+ public final String getName() {
+ return wrapped().getName();
+ }
+
+ // -----------------------------------------------------------------
+ // Generic methods taking a Level as parameter
+ // -----------------------------------------------------------------
+
+
+ @Override
+ public boolean isLoggable(Level level) {
+ return wrapped().isLoggable(level);
+ }
+
+ @Override
+ public void log(Level level, String msg) {
+ wrapped().log(level, msg);
+ }
+
+ @Override
+ public void log(Level level,
+ Supplier<String> msgSupplier) {
+ wrapped().log(level, msgSupplier);
+ }
+
+ @Override
+ public void log(Level level, Object obj) {
+ wrapped().log(level, obj);
+ }
+
+ @Override
+ public void log(Level level,
+ String msg, Throwable thrown) {
+ wrapped().log(level, msg, thrown);
+ }
+
+ @Override
+ public void log(Level level, Supplier<String> msgSupplier, Throwable thrown) {
+ wrapped().log(level, msgSupplier, thrown);
+ }
+
+ @Override
+ public void log(Level level,
+ String format, Object... params) {
+ wrapped().log(level, format, params);
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle,
+ String key, Throwable thrown) {
+ wrapped().log(level, bundle, key, thrown);
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle,
+ String format, Object... params) {
+ wrapped().log(level, bundle, format, params);
+ }
+
+ // ---------------------------------------------------------
+ // Methods from PlatformLogger.Bridge
+ // ---------------------------------------------------------
+
+ @Override
+ public boolean isLoggable(PlatformLogger.Level level) {
+ final PlatformLogger.Bridge platformProxy = platformProxy();
+ if (platformProxy == null) return isLoggable(level.systemLevel());
+ else return platformProxy.isLoggable(level);
+ }
+
+ @Override
+ public boolean isEnabled() {
+ final PlatformLogger.Bridge platformProxy = platformProxy();
+ return platformProxy == null || platformProxy.isEnabled();
+ }
+
+ @Override
+ public void log(PlatformLogger.Level level, String msg) {
+ final PlatformLogger.Bridge platformProxy = platformProxy();
+ if (platformProxy == null) {
+ wrapped().log(level.systemLevel(), msg);
+ } else {
+ platformProxy.log(level, msg);
+ }
+ }
+
+ @Override
+ public void log(PlatformLogger.Level level, String msg, Throwable thrown) {
+ final PlatformLogger.Bridge platformProxy = platformProxy();
+ if (platformProxy == null) {
+ wrapped().log(level.systemLevel(), msg, thrown);
+ } else {
+ platformProxy.log(level, msg, thrown);
+ }
+ }
+
+ @Override
+ public void log(PlatformLogger.Level level, String msg, Object... params) {
+ final PlatformLogger.Bridge platformProxy = platformProxy();
+ if (platformProxy == null) {
+ wrapped().log(level.systemLevel(), msg, params);
+ } else {
+ platformProxy.log(level, msg, params);
+ }
+ }
+
+ @Override
+ public void log(PlatformLogger.Level level, Supplier<String> msgSupplier) {
+ final PlatformLogger.Bridge platformProxy = platformProxy();
+ if (platformProxy == null) {
+ wrapped().log(level.systemLevel(),msgSupplier);
+ } else {
+ platformProxy.log(level,msgSupplier);
+ }
+ }
+
+ @Override
+ public void log(PlatformLogger.Level level, Throwable thrown,
+ Supplier<String> msgSupplier) {
+ final PlatformLogger.Bridge platformProxy = platformProxy();
+ if (platformProxy == null) {
+ wrapped().log(level.systemLevel(), msgSupplier, thrown);
+ } else {
+ platformProxy.log(level, thrown, msgSupplier);
+ }
+ }
+
+ @Override
+ public void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, String msg) {
+ final PlatformLogger.Bridge platformProxy = platformProxy();
+ if (platformProxy == null) {
+ if (sourceClass == null && sourceMethod == null) { // best effort
+ wrapped().log(level.systemLevel(), msg);
+ } else {
+ Level systemLevel = level.systemLevel();
+ Logger wrapped = wrapped();
+ if (wrapped.isLoggable(systemLevel)) {
+ sourceClass = sourceClass == null ? "" : sourceClass;
+ sourceMethod = sourceMethod == null ? "" : sourceMethod;
+ msg = msg == null ? "" : msg;
+ wrapped.log(systemLevel, String.format("[%s %s] %s",
+ sourceClass, sourceMethod, msg));
+ }
+ }
+ } else {
+ platformProxy.logp(level, sourceClass, sourceMethod, msg);
+ }
+ }
+
+ @Override
+ public void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, Supplier<String> msgSupplier) {
+ final PlatformLogger.Bridge platformProxy = platformProxy();
+ if (platformProxy == null) { // best effort
+ if (sourceClass == null && sourceMethod == null) {
+ wrapped().log(level.systemLevel(), msgSupplier);
+ } else {
+ Level systemLevel = level.systemLevel();
+ Logger wrapped = wrapped();
+ if (wrapped.isLoggable(systemLevel)) {
+ final String sClass = sourceClass == null ? "" : sourceClass;
+ final String sMethod = sourceMethod == null ? "" : sourceMethod;
+ wrapped.log(systemLevel, () -> String.format("[%s %s] %s",
+ sClass, sMethod, msgSupplier.get()));
+ }
+ }
+ } else {
+ platformProxy.logp(level, sourceClass, sourceMethod, msgSupplier);
+ }
+ }
+
+ @Override
+ public void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, String msg, Object... params) {
+ final PlatformLogger.Bridge platformProxy = platformProxy();
+ if (platformProxy == null) { // best effort
+ if (sourceClass == null && sourceMethod == null) {
+ wrapped().log(level.systemLevel(), msg, params);
+ } else {
+ Level systemLevel = level.systemLevel();
+ Logger wrapped = wrapped();
+ if (wrapped.isLoggable(systemLevel)) {
+ sourceClass = sourceClass == null ? "" : sourceClass;
+ sourceMethod = sourceMethod == null ? "" : sourceMethod;
+ msg = msg == null ? "" : msg;
+ wrapped.log(systemLevel, String.format("[%s %s] %s",
+ sourceClass, sourceMethod, msg), params);
+ }
+ }
+ } else {
+ platformProxy.logp(level, sourceClass, sourceMethod, msg, params);
+ }
+ }
+
+ @Override
+ public void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, String msg, Throwable thrown) {
+ final PlatformLogger.Bridge platformProxy = platformProxy();
+ if (platformProxy == null) { // best effort
+ if (sourceClass == null && sourceMethod == null) {
+ wrapped().log(level.systemLevel(), msg, thrown);
+ } else {
+ Level systemLevel = level.systemLevel();
+ Logger wrapped = wrapped();
+ if (wrapped.isLoggable(systemLevel)) {
+ sourceClass = sourceClass == null ? "" : sourceClass;
+ sourceMethod = sourceMethod == null ? "" : sourceMethod;
+ msg = msg == null ? "" : msg;
+ wrapped.log(systemLevel, String.format("[%s %s] %s",
+ sourceClass, sourceMethod, msg), thrown);
+ }
+ }
+ } else {
+ platformProxy.logp(level, sourceClass, sourceMethod, msg, thrown);
+ }
+ }
+
+ @Override
+ public void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, Throwable thrown,
+ Supplier<String> msgSupplier) {
+ final PlatformLogger.Bridge platformProxy = platformProxy();
+ if (platformProxy == null) { // best effort
+ if (sourceClass == null && sourceMethod == null) {
+ wrapped().log(level.systemLevel(), msgSupplier, thrown);
+ } else {
+ Level systemLevel = level.systemLevel();
+ Logger wrapped = wrapped();
+ if (wrapped.isLoggable(systemLevel)) {
+ final String sClass = sourceClass == null ? "" : sourceClass;
+ final String sMethod = sourceMethod == null ? "" : sourceMethod;
+ wrapped.log(systemLevel, () -> String.format("[%s %s] %s",
+ sClass, sMethod, msgSupplier.get()), thrown);
+ }
+ }
+ } else {
+ platformProxy.logp(level, sourceClass, sourceMethod,
+ thrown, msgSupplier);
+ }
+ }
+
+ @Override
+ public void logrb(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, ResourceBundle bundle,
+ String msg, Object... params) {
+ final PlatformLogger.Bridge platformProxy = platformProxy();
+ if (platformProxy == null) { // best effort
+ if (bundle != null || sourceClass == null && sourceMethod == null) {
+ wrapped().log(level.systemLevel(), bundle, msg, params);
+ } else {
+ Level systemLevel = level.systemLevel();
+ Logger wrapped = wrapped();
+ if (wrapped.isLoggable(systemLevel)) {
+ sourceClass = sourceClass == null ? "" : sourceClass;
+ sourceMethod = sourceMethod == null ? "" : sourceMethod;
+ msg = msg == null ? "" : msg;
+ wrapped.log(systemLevel, bundle, String.format("[%s %s] %s",
+ sourceClass, sourceMethod, msg), params);
+ }
+ }
+ } else {
+ platformProxy.logrb(level, sourceClass, sourceMethod,
+ bundle, msg, params);
+ }
+ }
+
+ @Override
+ public void logrb(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, ResourceBundle bundle, String msg,
+ Throwable thrown) {
+ final PlatformLogger.Bridge platformProxy = platformProxy();
+ if (platformProxy == null) { // best effort
+ if (bundle != null || sourceClass == null && sourceMethod == null) {
+ wrapped().log(level.systemLevel(), bundle, msg, thrown);
+ } else {
+ Level systemLevel = level.systemLevel();
+ Logger wrapped = wrapped();
+ if (wrapped.isLoggable(systemLevel)) {
+ sourceClass = sourceClass == null ? "" : sourceClass;
+ sourceMethod = sourceMethod == null ? "" : sourceMethod;
+ msg = msg == null ? "" : msg;
+ wrapped.log(systemLevel, bundle, String.format("[%s %s] %s",
+ sourceClass, sourceMethod, msg), thrown);
+ }
+ }
+ } else {
+ platformProxy.logrb(level, sourceClass, sourceMethod, bundle,
+ msg, thrown);
+ }
+ }
+
+ @Override
+ public void logrb(PlatformLogger.Level level, ResourceBundle bundle,
+ String msg, Throwable thrown) {
+ final PlatformLogger.Bridge platformProxy = platformProxy();
+ if (platformProxy == null) {
+ wrapped().log(level.systemLevel(), bundle, msg, thrown);
+ } else {
+ platformProxy.logrb(level, bundle, msg, thrown);
+ }
+ }
+
+ @Override
+ public void logrb(PlatformLogger.Level level, ResourceBundle bundle,
+ String msg, Object... params) {
+ final PlatformLogger.Bridge platformProxy = platformProxy();
+ if (platformProxy == null) {
+ wrapped().log(level.systemLevel(), bundle, msg, params);
+ } else {
+ platformProxy.logrb(level, bundle, msg, params);
+ }
+ }
+
+
+ @Override
+ public LoggerConfiguration getLoggerConfiguration() {
+ final PlatformLogger.Bridge platformProxy = platformProxy();
+ return platformProxy == null ? null
+ : PlatformLogger.ConfigurableBridge
+ .getLoggerConfiguration(platformProxy);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/logger/BootstrapLogger.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,1074 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.logger;
+
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.ServiceLoader;
+import java.util.function.BooleanSupplier;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.lang.System.LoggerFinder;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.lang.ref.WeakReference;
+import java.util.Objects;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import sun.misc.InnocuousThread;
+import sun.misc.VM;
+import sun.util.logging.PlatformLogger;
+import jdk.internal.logger.LazyLoggers.LazyLoggerAccessor;
+
+/**
+ * The BootstrapLogger class handles all the logic needed by Lazy Loggers
+ * to delay the creation of System.Logger instances until the VM is booted.
+ * By extension - it also contains the logic that will delay the creation
+ * of JUL Loggers until the LogManager is initialized by the application, in
+ * the common case where JUL is the default and there is no custom JUL
+ * configuration.
+ *
+ * A BootstrapLogger instance is both a Logger and a
+ * PlatformLogger.Bridge instance, which will put all Log messages in a queue
+ * until the VM is booted.
+ * Once the VM is booted, it obtain the real System.Logger instance from the
+ * LoggerFinder and flushes the message to the queue.
+ *
+ * There are a few caveat:
+ * - the queue may not be flush until the next message is logged after
+ * the VM is booted
+ * - while the BootstrapLogger is active, the default implementation
+ * for all convenience methods is used
+ * - PlatformLogger.setLevel calls are ignored
+ *
+ *
+ */
+public final class BootstrapLogger implements Logger, PlatformLogger.Bridge,
+ PlatformLogger.ConfigurableBridge {
+
+ // We use the BootstrapExecutors class to submit delayed messages
+ // to an independent InnocuousThread which will ensure that
+ // delayed log events will be clearly identified as messages that have
+ // been delayed during the boot sequence.
+ private static class BootstrapExecutors implements ThreadFactory {
+
+ // Maybe that should be made configurable with system properties.
+ static final long KEEP_EXECUTOR_ALIVE_SECONDS = 30;
+
+ // The BootstrapMessageLoggerTask is a Runnable which keeps
+ // a hard ref to the ExecutorService that owns it.
+ // This ensure that the ExecutorService is not gc'ed until the thread
+ // has stopped running.
+ private static class BootstrapMessageLoggerTask implements Runnable {
+ ExecutorService owner;
+ Runnable run;
+ public BootstrapMessageLoggerTask(ExecutorService owner, Runnable r) {
+ this.owner = owner;
+ this.run = r;
+ }
+ @Override
+ public void run() {
+ try {
+ run.run();
+ } finally {
+ owner = null; // allow the ExecutorService to be gced.
+ }
+ }
+ }
+
+ private static volatile WeakReference<ExecutorService> executorRef;
+ private static ExecutorService getExecutor() {
+ WeakReference<ExecutorService> ref = executorRef;
+ ExecutorService executor = ref == null ? null : ref.get();
+ if (executor != null) return executor;
+ synchronized (BootstrapExecutors.class) {
+ ref = executorRef;
+ executor = ref == null ? null : ref.get();
+ if (executor == null) {
+ executor = new ThreadPoolExecutor(0, 1,
+ KEEP_EXECUTOR_ALIVE_SECONDS, TimeUnit.SECONDS,
+ new LinkedBlockingQueue<>(), new BootstrapExecutors());
+ }
+ // The executor service will be elligible for gc
+ // KEEP_EXECUTOR_ALIVE_SECONDS seconds (30s)
+ // after the execution of its last pending task.
+ executorRef = new WeakReference<>(executor);
+ return executorRef.get();
+ }
+ }
+
+ @Override
+ public Thread newThread(Runnable r) {
+ ExecutorService owner = getExecutor();
+ Thread thread = AccessController.doPrivileged(new PrivilegedAction<Thread>() {
+ @Override
+ public Thread run() {
+ Thread t = new InnocuousThread(new BootstrapMessageLoggerTask(owner, r));
+ t.setName("BootstrapMessageLoggerTask-"+t.getName());
+ return t;
+ }
+ }, null, new RuntimePermission("enableContextClassLoaderOverride"));
+ thread.setDaemon(true);
+ return thread;
+ }
+
+ static void submit(Runnable r) {
+ getExecutor().execute(r);
+ }
+
+ // This is used by tests.
+ static void join(Runnable r) {
+ try {
+ getExecutor().submit(r).get();
+ } catch (InterruptedException | ExecutionException ex) {
+ // should not happen
+ throw new RuntimeException(ex);
+ }
+ }
+
+ // This is used by tests.
+ static void awaitPendingTasks() {
+ WeakReference<ExecutorService> ref = executorRef;
+ ExecutorService executor = ref == null ? null : ref.get();
+ if (ref == null) {
+ synchronized(BootstrapExecutors.class) {
+ ref = executorRef;
+ executor = ref == null ? null : ref.get();
+ }
+ }
+ if (executor != null) {
+ // since our executor uses a FIFO and has a single thread
+ // then awaiting the execution of its pending tasks can be done
+ // simply by registering a new task and waiting until it
+ // completes. This of course would not work if we were using
+ // several threads, but we don't.
+ join(()->{});
+ }
+ }
+
+ // This is used by tests.
+ static boolean isAlive() {
+ WeakReference<ExecutorService> ref = executorRef;
+ ExecutorService executor = ref == null ? null : ref.get();
+ if (executor != null) return true;
+ synchronized (BootstrapExecutors.class) {
+ ref = executorRef;
+ executor = ref == null ? null : ref.get();
+ return executor != null;
+ }
+ }
+
+ // The pending log event queue. The first event is the head, and
+ // new events are added at the tail
+ static LogEvent head, tail;
+
+ static void enqueue(LogEvent event) {
+ if (event.next != null) return;
+ synchronized (BootstrapExecutors.class) {
+ if (event.next != null) return;
+ event.next = event;
+ if (tail == null) {
+ head = tail = event;
+ } else {
+ tail.next = event;
+ tail = event;
+ }
+ }
+ }
+
+ static void flush() {
+ LogEvent event;
+ // drain the whole queue
+ synchronized(BootstrapExecutors.class) {
+ event = head;
+ head = tail = null;
+ }
+ while(event != null) {
+ LogEvent.log(event);
+ synchronized(BootstrapExecutors.class) {
+ LogEvent prev = event;
+ event = (event.next == event ? null : event.next);
+ prev.next = null;
+ }
+ }
+ }
+ }
+
+ // The accessor in which this logger is temporarily set.
+ final LazyLoggerAccessor holder;
+
+ BootstrapLogger(LazyLoggerAccessor holder) {
+ this.holder = holder;
+ }
+
+ // Temporary data object storing log events
+ // It would be nice to use a Consumer<Logger> instead of a LogEvent.
+ // This way we could simply do things like:
+ // push((logger) -> logger.log(level, msg));
+ // Unfortunately, if we come to here it means we are in the bootsraping
+ // phase where using lambdas is not safe yet - so we have to use a
+ // a data object instead...
+ //
+ static final class LogEvent {
+ // only one of these two levels should be non null
+ final Level level;
+ final PlatformLogger.Level platformLevel;
+ final BootstrapLogger bootstrap;
+
+ final ResourceBundle bundle;
+ final String msg;
+ final Throwable thrown;
+ final Object[] params;
+ final Supplier<String> msgSupplier;
+ final String sourceClass;
+ final String sourceMethod;
+ final long timeMillis;
+ final long nanoAdjustment;
+
+ // because logging a message may entail calling toString() on
+ // the parameters etc... we need to store the context of the
+ // caller who logged the message - so that we can reuse it when
+ // we finally log the message.
+ final AccessControlContext acc;
+
+ // The next event in the queue
+ LogEvent next;
+
+ private LogEvent(BootstrapLogger bootstrap, Level level,
+ ResourceBundle bundle, String msg,
+ Throwable thrown, Object[] params) {
+ this.acc = AccessController.getContext();
+ this.timeMillis = System.currentTimeMillis();
+ this.nanoAdjustment = VM.getNanoTimeAdjustment(timeMillis);
+ this.level = level;
+ this.platformLevel = null;
+ this.bundle = bundle;
+ this.msg = msg;
+ this.msgSupplier = null;
+ this.thrown = thrown;
+ this.params = params;
+ this.sourceClass = null;
+ this.sourceMethod = null;
+ this.bootstrap = bootstrap;
+ }
+
+ private LogEvent(BootstrapLogger bootstrap, Level level,
+ Supplier<String> msgSupplier,
+ Throwable thrown, Object[] params) {
+ this.acc = AccessController.getContext();
+ this.timeMillis = System.currentTimeMillis();
+ this.nanoAdjustment = VM.getNanoTimeAdjustment(timeMillis);
+ this.level = level;
+ this.platformLevel = null;
+ this.bundle = null;
+ this.msg = null;
+ this.msgSupplier = msgSupplier;
+ this.thrown = thrown;
+ this.params = params;
+ this.sourceClass = null;
+ this.sourceMethod = null;
+ this.bootstrap = bootstrap;
+ }
+
+ private LogEvent(BootstrapLogger bootstrap,
+ PlatformLogger.Level platformLevel,
+ String sourceClass, String sourceMethod,
+ ResourceBundle bundle, String msg,
+ Throwable thrown, Object[] params) {
+ this.acc = AccessController.getContext();
+ this.timeMillis = System.currentTimeMillis();
+ this.nanoAdjustment = VM.getNanoTimeAdjustment(timeMillis);
+ this.level = null;
+ this.platformLevel = platformLevel;
+ this.bundle = bundle;
+ this.msg = msg;
+ this.msgSupplier = null;
+ this.thrown = thrown;
+ this.params = params;
+ this.sourceClass = sourceClass;
+ this.sourceMethod = sourceMethod;
+ this.bootstrap = bootstrap;
+ }
+
+ private LogEvent(BootstrapLogger bootstrap,
+ PlatformLogger.Level platformLevel,
+ String sourceClass, String sourceMethod,
+ Supplier<String> msgSupplier,
+ Throwable thrown, Object[] params) {
+ this.acc = AccessController.getContext();
+ this.timeMillis = System.currentTimeMillis();
+ this.nanoAdjustment = VM.getNanoTimeAdjustment(timeMillis);
+ this.level = null;
+ this.platformLevel = platformLevel;
+ this.bundle = null;
+ this.msg = null;
+ this.msgSupplier = msgSupplier;
+ this.thrown = thrown;
+ this.params = params;
+ this.sourceClass = sourceClass;
+ this.sourceMethod = sourceMethod;
+ this.bootstrap = bootstrap;
+ }
+
+ // Log this message in the given logger. Do not call directly.
+ // Use LogEvent.log(LogEvent, logger) instead.
+ private void log(Logger logger) {
+ assert platformLevel == null && level != null;
+ //new Exception("logging delayed message").printStackTrace();
+ if (msgSupplier != null) {
+ if (thrown != null) {
+ logger.log(level, msgSupplier, thrown);
+ } else {
+ logger.log(level, msgSupplier);
+ }
+ } else {
+ // BootstrapLoggers are never localized so we can safely
+ // use the method that takes a ResourceBundle parameter
+ // even when that resource bundle is null.
+ if (thrown != null) {
+ logger.log(level, bundle, msg, thrown);
+ } else {
+ logger.log(level, bundle, msg, params);
+ }
+ }
+ }
+
+ // Log this message in the given logger. Do not call directly.
+ // Use LogEvent.doLog(LogEvent, logger) instead.
+ private void log(PlatformLogger.Bridge logger) {
+ assert platformLevel != null && level == null;
+ if (sourceClass == null) {
+ if (msgSupplier != null) {
+ if (thrown != null) {
+ logger.log(platformLevel, thrown, msgSupplier);
+ } else {
+ logger.log(platformLevel, msgSupplier);
+ }
+ } else {
+ // BootstrapLoggers are never localized so we can safely
+ // use the method that takes a ResourceBundle parameter
+ // even when that resource bundle is null.
+ if (thrown != null) {
+ logger.logrb(platformLevel, bundle, msg, thrown);
+ } else {
+ logger.logrb(platformLevel, bundle, msg, params);
+ }
+ }
+ } else {
+ if (msgSupplier != null) {
+ if (thrown != null) {
+ logger.log(platformLevel, sourceClass, sourceMethod, thrown, msgSupplier);
+ } else {
+ logger.log(platformLevel,sourceClass, sourceMethod, msgSupplier);
+ }
+ } else {
+ // BootstrapLoggers are never localized so we can safely
+ // use the method that takes a ResourceBundle parameter
+ // even when that resource bundle is null.
+ if (thrown != null) {
+ logger.logrb(platformLevel, sourceClass, sourceMethod, bundle, msg, thrown);
+ } else {
+ logger.logrb(platformLevel, sourceClass, sourceMethod, bundle, msg, params);
+ }
+ }
+ }
+ }
+
+ // non default methods from Logger interface
+ static LogEvent valueOf(BootstrapLogger bootstrap, Level level,
+ ResourceBundle bundle, String key, Throwable thrown) {
+ return new LogEvent(Objects.requireNonNull(bootstrap),
+ Objects.requireNonNull(level), bundle, key,
+ thrown, null);
+ }
+ static LogEvent valueOf(BootstrapLogger bootstrap, Level level,
+ ResourceBundle bundle, String format, Object[] params) {
+ return new LogEvent(Objects.requireNonNull(bootstrap),
+ Objects.requireNonNull(level), bundle, format,
+ null, params);
+ }
+ static LogEvent valueOf(BootstrapLogger bootstrap, Level level,
+ Supplier<String> msgSupplier, Throwable thrown) {
+ return new LogEvent(Objects.requireNonNull(bootstrap),
+ Objects.requireNonNull(level),
+ Objects.requireNonNull(msgSupplier), thrown, null);
+ }
+ static LogEvent valueOf(BootstrapLogger bootstrap, Level level,
+ Supplier<String> msgSupplier) {
+ return new LogEvent(Objects.requireNonNull(bootstrap),
+ Objects.requireNonNull(level),
+ Objects.requireNonNull(msgSupplier), null, null);
+ }
+ static void log(LogEvent log, Logger logger) {
+ final SecurityManager sm = System.getSecurityManager();
+ // not sure we can actually use lambda here. We may need to create
+ // an anonymous class. Although if we reach here, then it means
+ // the VM is booted.
+ if (sm == null || log.acc == null) {
+ BootstrapExecutors.submit(() -> log.log(logger));
+ } else {
+ BootstrapExecutors.submit(() ->
+ AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
+ log.log(logger); return null;
+ }, log.acc));
+ }
+ }
+
+ // non default methods from PlatformLogger.Bridge interface
+ static LogEvent valueOf(BootstrapLogger bootstrap,
+ PlatformLogger.Level level, String msg) {
+ return new LogEvent(Objects.requireNonNull(bootstrap),
+ Objects.requireNonNull(level), null, null, null,
+ msg, null, null);
+ }
+ static LogEvent valueOf(BootstrapLogger bootstrap, PlatformLogger.Level level,
+ String msg, Throwable thrown) {
+ return new LogEvent(Objects.requireNonNull(bootstrap),
+ Objects.requireNonNull(level), null, null, null, msg, thrown, null);
+ }
+ static LogEvent valueOf(BootstrapLogger bootstrap, PlatformLogger.Level level,
+ String msg, Object[] params) {
+ return new LogEvent(Objects.requireNonNull(bootstrap),
+ Objects.requireNonNull(level), null, null, null, msg, null, params);
+ }
+ static LogEvent valueOf(BootstrapLogger bootstrap, PlatformLogger.Level level,
+ Supplier<String> msgSupplier) {
+ return new LogEvent(Objects.requireNonNull(bootstrap),
+ Objects.requireNonNull(level), null, null, msgSupplier, null, null);
+ }
+ static LogEvent vaueOf(BootstrapLogger bootstrap, PlatformLogger.Level level,
+ Supplier<String> msgSupplier,
+ Throwable thrown) {
+ return new LogEvent(Objects.requireNonNull(bootstrap),
+ Objects.requireNonNull(level), null, null,
+ msgSupplier, thrown, null);
+ }
+ static LogEvent valueOf(BootstrapLogger bootstrap, PlatformLogger.Level level,
+ String sourceClass, String sourceMethod,
+ ResourceBundle bundle, String msg, Object[] params) {
+ return new LogEvent(Objects.requireNonNull(bootstrap),
+ Objects.requireNonNull(level), sourceClass,
+ sourceMethod, bundle, msg, null, params);
+ }
+ static LogEvent valueOf(BootstrapLogger bootstrap, PlatformLogger.Level level,
+ String sourceClass, String sourceMethod,
+ ResourceBundle bundle, String msg, Throwable thrown) {
+ return new LogEvent(Objects.requireNonNull(bootstrap),
+ Objects.requireNonNull(level), sourceClass,
+ sourceMethod, bundle, msg, thrown, null);
+ }
+ static LogEvent valueOf(BootstrapLogger bootstrap, PlatformLogger.Level level,
+ String sourceClass, String sourceMethod,
+ Supplier<String> msgSupplier, Throwable thrown) {
+ return new LogEvent(Objects.requireNonNull(bootstrap),
+ Objects.requireNonNull(level), sourceClass,
+ sourceMethod, msgSupplier, thrown, null);
+ }
+ static void log(LogEvent log, PlatformLogger.Bridge logger) {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm == null || log.acc == null) {
+ log.log(logger);
+ } else {
+ // not sure we can actually use lambda here. We may need to create
+ // an anonymous class. Although if we reach here, then it means
+ // the VM is booted.
+ AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
+ log.log(logger); return null;
+ }, log.acc);
+ }
+ }
+
+ static void log(LogEvent event) {
+ event.bootstrap.flush(event);
+ }
+
+ }
+
+ // Push a log event at the end of the pending LogEvent queue.
+ void push(LogEvent log) {
+ BootstrapExecutors.enqueue(log);
+ // if the queue has been flushed just before we entered
+ // the synchronized block we need to flush it again.
+ checkBootstrapping();
+ }
+
+ // Flushes the queue of pending LogEvents to the logger.
+ void flush(LogEvent event) {
+ assert event.bootstrap == this;
+ if (event.platformLevel != null) {
+ PlatformLogger.Bridge concrete = holder.getConcretePlatformLogger(this);
+ LogEvent.log(event, concrete);
+ } else {
+ Logger concrete = holder.getConcreteLogger(this);
+ LogEvent.log(event, concrete);
+ }
+ }
+
+ /**
+ * The name of this logger. This is the name of the actual logger for which
+ * this logger acts as a temporary proxy.
+ * @return The logger name.
+ */
+ @Override
+ public String getName() {
+ return holder.name;
+ }
+
+ /**
+ * Check whether the VM is still bootstrapping, and if not, arranges
+ * for this logger's holder to create the real logger and flush the
+ * pending event queue.
+ * @return true if the VM is still bootstrapping.
+ */
+ boolean checkBootstrapping() {
+ if (isBooted()) {
+ BootstrapExecutors.flush();
+ return false;
+ }
+ return true;
+ }
+
+ // ----------------------------------
+ // Methods from Logger
+ // ----------------------------------
+
+ @Override
+ public boolean isLoggable(Level level) {
+ if (checkBootstrapping()) {
+ return level.getSeverity() >= Level.INFO.getSeverity();
+ } else {
+ final Logger spi = holder.wrapped();
+ return spi.isLoggable(level);
+ }
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle, String key, Throwable thrown) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, bundle, key, thrown));
+ } else {
+ final Logger spi = holder.wrapped();
+ spi.log(level, bundle, key, thrown);
+ }
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle, String format, Object... params) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, bundle, format, params));
+ } else {
+ final Logger spi = holder.wrapped();
+ spi.log(level, bundle, format, params);
+ }
+ }
+
+ @Override
+ public void log(Level level, String msg, Throwable thrown) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, null, msg, thrown));
+ } else {
+ final Logger spi = holder.wrapped();
+ spi.log(level, msg, thrown);
+ }
+ }
+
+ @Override
+ public void log(Level level, String format, Object... params) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, null, format, params));
+ } else {
+ final Logger spi = holder.wrapped();
+ spi.log(level, format, params);
+ }
+ }
+
+ @Override
+ public void log(Level level, Supplier<String> msgSupplier) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, msgSupplier));
+ } else {
+ final Logger spi = holder.wrapped();
+ spi.log(level, msgSupplier);
+ }
+ }
+
+ @Override
+ public void log(Level level, Object obj) {
+ if (checkBootstrapping()) {
+ Logger.super.log(level, obj);
+ } else {
+ final Logger spi = holder.wrapped();
+ spi.log(level, obj);
+ }
+ }
+
+ @Override
+ public void log(Level level, String msg) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, null, msg, (Object[])null));
+ } else {
+ final Logger spi = holder.wrapped();
+ spi.log(level, msg);
+ }
+ }
+
+ @Override
+ public void log(Level level, Supplier<String> msgSupplier, Throwable thrown) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, msgSupplier, thrown));
+ } else {
+ final Logger spi = holder.wrapped();
+ spi.log(level, msgSupplier, thrown);
+ }
+ }
+
+ // ----------------------------------
+ // Methods from PlatformLogger.Bridge
+ // ----------------------------------
+
+ @Override
+ public boolean isLoggable(PlatformLogger.Level level) {
+ if (checkBootstrapping()) {
+ return level.intValue() >= PlatformLogger.Level.INFO.intValue();
+ } else {
+ final PlatformLogger.Bridge spi = holder.platform();
+ return spi.isLoggable(level);
+ }
+ }
+
+ @Override
+ public boolean isEnabled() {
+ if (checkBootstrapping()) {
+ return true;
+ } else {
+ final PlatformLogger.Bridge spi = holder.platform();
+ return spi.isEnabled();
+ }
+ }
+
+ @Override
+ public void log(PlatformLogger.Level level, String msg) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, msg));
+ } else {
+ final PlatformLogger.Bridge spi = holder.platform();
+ spi.log(level, msg);
+ }
+ }
+
+ @Override
+ public void log(PlatformLogger.Level level, String msg, Throwable thrown) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, msg, thrown));
+ } else {
+ final PlatformLogger.Bridge spi = holder.platform();
+ spi.log(level, msg, thrown);
+ }
+ }
+
+ @Override
+ public void log(PlatformLogger.Level level, String msg, Object... params) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, msg, params));
+ } else {
+ final PlatformLogger.Bridge spi = holder.platform();
+ spi.log(level, msg, params);
+ }
+ }
+
+ @Override
+ public void log(PlatformLogger.Level level, Supplier<String> msgSupplier) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, msgSupplier));
+ } else {
+ final PlatformLogger.Bridge spi = holder.platform();
+ spi.log(level, msgSupplier);
+ }
+ }
+
+ @Override
+ public void log(PlatformLogger.Level level, Throwable thrown,
+ Supplier<String> msgSupplier) {
+ if (checkBootstrapping()) {
+ push(LogEvent.vaueOf(this, level, msgSupplier, thrown));
+ } else {
+ final PlatformLogger.Bridge spi = holder.platform();
+ spi.log(level, thrown, msgSupplier);
+ }
+ }
+
+ @Override
+ public void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, String msg) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, sourceClass, sourceMethod, null,
+ msg, (Object[])null));
+ } else {
+ final PlatformLogger.Bridge spi = holder.platform();
+ spi.logp(level, sourceClass, sourceMethod, msg);
+ }
+ }
+
+ @Override
+ public void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, Supplier<String> msgSupplier) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, sourceClass, sourceMethod, msgSupplier, null));
+ } else {
+ final PlatformLogger.Bridge spi = holder.platform();
+ spi.logp(level, sourceClass, sourceMethod, msgSupplier);
+ }
+ }
+
+ @Override
+ public void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, String msg, Object... params) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, sourceClass, sourceMethod, null, msg, params));
+ } else {
+ final PlatformLogger.Bridge spi = holder.platform();
+ spi.logp(level, sourceClass, sourceMethod, msg, params);
+ }
+ }
+
+ @Override
+ public void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, String msg, Throwable thrown) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, sourceClass, sourceMethod, null, msg, thrown));
+ } else {
+ final PlatformLogger.Bridge spi = holder.platform();
+ spi.logp(level, sourceClass, sourceMethod, msg, thrown);
+ }
+ }
+
+ @Override
+ public void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, Throwable thrown, Supplier<String> msgSupplier) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, sourceClass, sourceMethod, msgSupplier, thrown));
+ } else {
+ final PlatformLogger.Bridge spi = holder.platform();
+ spi.logp(level, sourceClass, sourceMethod, thrown, msgSupplier);
+ }
+ }
+
+ @Override
+ public void logrb(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, ResourceBundle bundle, String msg, Object... params) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, sourceClass, sourceMethod, bundle, msg, params));
+ } else {
+ final PlatformLogger.Bridge spi = holder.platform();
+ spi.logrb(level, sourceClass, sourceMethod, bundle, msg, params);
+ }
+ }
+
+ @Override
+ public void logrb(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, ResourceBundle bundle, String msg, Throwable thrown) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, sourceClass, sourceMethod, bundle, msg, thrown));
+ } else {
+ final PlatformLogger.Bridge spi = holder.platform();
+ spi.logrb(level, sourceClass, sourceMethod, bundle, msg, thrown);
+ }
+ }
+
+ @Override
+ public void logrb(PlatformLogger.Level level, ResourceBundle bundle,
+ String msg, Object... params) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, null, null, bundle, msg, params));
+ } else {
+ final PlatformLogger.Bridge spi = holder.platform();
+ spi.logrb(level, bundle, msg, params);
+ }
+ }
+
+ @Override
+ public void logrb(PlatformLogger.Level level, ResourceBundle bundle, String msg, Throwable thrown) {
+ if (checkBootstrapping()) {
+ push(LogEvent.valueOf(this, level, null, null, bundle, msg, thrown));
+ } else {
+ final PlatformLogger.Bridge spi = holder.platform();
+ spi.logrb(level, bundle, msg, thrown);
+ }
+ }
+
+ @Override
+ public LoggerConfiguration getLoggerConfiguration() {
+ if (checkBootstrapping()) {
+ // This practically means that PlatformLogger.setLevel()
+ // calls will be ignored if the VM is still bootstrapping. We could
+ // attempt to fix that but is it worth it?
+ return PlatformLogger.ConfigurableBridge.super.getLoggerConfiguration();
+ } else {
+ final PlatformLogger.Bridge spi = holder.platform();
+ return PlatformLogger.ConfigurableBridge.getLoggerConfiguration(spi);
+ }
+ }
+
+ // This BooleanSupplier is a hook for tests - so that we can simulate
+ // what would happen before the VM is booted.
+ private static volatile BooleanSupplier isBooted;
+ public static boolean isBooted() {
+ if (isBooted != null) return isBooted.getAsBoolean();
+ else return VM.isBooted();
+ }
+
+ // A bit of black magic. We try to find out the nature of the logging
+ // backend without actually loading it.
+ private static enum LoggingBackend {
+ // There is no LoggerFinder and JUL is not present
+ NONE(true),
+
+ // There is no LoggerFinder, but we have found a
+ // JdkLoggerFinder installed (which means JUL is present),
+ // and we haven't found any custom configuration for JUL.
+ // Until LogManager is initialized we can use a simple console
+ // logger.
+ JUL_DEFAULT(false),
+
+ // Same as above, except that we have found a custom configuration
+ // for JUL. We cannot use the simple console logger in this case.
+ JUL_WITH_CONFIG(true),
+
+ // We have found a custom LoggerFinder.
+ CUSTOM(true);
+
+ final boolean useLoggerFinder;
+ private LoggingBackend(boolean useLoggerFinder) {
+ this.useLoggerFinder = useLoggerFinder;
+ }
+ };
+
+ // The purpose of this class is to delay the initialization of
+ // the detectedBackend field until it is actually read.
+ // We do not want this field to get initialized if VM.isBooted() is false.
+ private static final class DetectBackend {
+ static final LoggingBackend detectedBackend;
+ static {
+ detectedBackend = AccessController.doPrivileged(new PrivilegedAction<LoggingBackend>() {
+ @Override
+ public LoggingBackend run() {
+ final Iterator<LoggerFinder> iterator =
+ ServiceLoader.load(LoggerFinder.class, ClassLoader.getSystemClassLoader())
+ .iterator();
+ if (iterator.hasNext()) {
+ return LoggingBackend.CUSTOM; // Custom Logger Provider is registered
+ }
+ // No custom logger provider: we will be using the default
+ // backend.
+ final Iterator<DefaultLoggerFinder> iterator2 =
+ ServiceLoader.loadInstalled(DefaultLoggerFinder.class)
+ .iterator();
+ if (iterator2.hasNext()) {
+ // LoggingProviderImpl is registered. The default
+ // implementation is java.util.logging
+ String cname = System.getProperty("java.util.logging.config.class");
+ String fname = System.getProperty("java.util.logging.config.file");
+ return (cname != null || fname != null)
+ ? LoggingBackend.JUL_WITH_CONFIG
+ : LoggingBackend.JUL_DEFAULT;
+ } else {
+ // SimpleLogger is used
+ return LoggingBackend.NONE;
+ }
+ }
+ });
+
+ }
+ }
+
+ // We will use temporary SimpleConsoleLoggers if
+ // the logging backend is JUL, there is no custom config,
+ // and the LogManager has not been initialized yet.
+ private static boolean useTemporaryLoggers() {
+ // being paranoid: this should already have been checked
+ if (!isBooted()) return true;
+ return DetectBackend.detectedBackend == LoggingBackend.JUL_DEFAULT
+ && !logManagerConfigured;
+ }
+
+ // We will use lazy loggers if:
+ // - the VM is not yet booted
+ // - the logging backend is a custom backend
+ // - the logging backend is JUL, there is no custom config,
+ // and the LogManager has not been initialized yet.
+ public static synchronized boolean useLazyLoggers() {
+ return !BootstrapLogger.isBooted()
+ || DetectBackend.detectedBackend == LoggingBackend.CUSTOM
+ || useTemporaryLoggers();
+ }
+
+ // Called by LazyLoggerAccessor. This method will determine whether
+ // to create a BootstrapLogger (if the VM is not yet booted),
+ // a SimpleConsoleLogger (if JUL is the default backend and there
+ // is no custom JUL configuration and LogManager is not yet initialized),
+ // or a logger returned by the loaded LoggerFinder (all other cases).
+ static Logger getLogger(LazyLoggerAccessor accessor) {
+ if (!BootstrapLogger.isBooted()) {
+ return new BootstrapLogger(accessor);
+ } else {
+ boolean temporary = useTemporaryLoggers();
+ if (temporary) {
+ // JUL is the default backend, there is no custom configuration,
+ // LogManager has not been used.
+ synchronized(BootstrapLogger.class) {
+ if (useTemporaryLoggers()) {
+ return makeTemporaryLogger(accessor);
+ }
+ }
+ }
+ // Already booted. Return the real logger.
+ return accessor.createLogger();
+ }
+ }
+
+
+ // If the backend is JUL, and there is no custom configuration, and
+ // nobody has attempted to call LogManager.getLogManager() yet, then
+ // we can temporarily substitute JUL Logger with SimpleConsoleLoggers,
+ // which avoids the cost of actually loading up the LogManager...
+ // The TemporaryLoggers class has the logic to create such temporary
+ // loggers, and to possibly replace them with real JUL loggers if
+ // someone calls LogManager.getLogManager().
+ static final class TemporaryLoggers implements
+ Function<LazyLoggerAccessor, SimpleConsoleLogger> {
+
+ // all accesses must be synchronized on the outer BootstrapLogger.class
+ final Map<LazyLoggerAccessor, SimpleConsoleLogger> temporaryLoggers =
+ new HashMap<>();
+
+ // all accesses must be synchronized on the outer BootstrapLogger.class
+ // The temporaryLoggers map will be cleared when LogManager is initialized.
+ boolean cleared;
+
+ @Override
+ // all accesses must be synchronized on the outer BootstrapLogger.class
+ public SimpleConsoleLogger apply(LazyLoggerAccessor t) {
+ if (cleared) throw new IllegalStateException("LoggerFinder already initialized");
+ return SimpleConsoleLogger.makeSimpleLogger(t.getLoggerName(), true);
+ }
+
+ // all accesses must be synchronized on the outer BootstrapLogger.class
+ SimpleConsoleLogger get(LazyLoggerAccessor a) {
+ if (cleared) throw new IllegalStateException("LoggerFinder already initialized");
+ return temporaryLoggers.computeIfAbsent(a, this);
+ }
+
+ // all accesses must be synchronized on the outer BootstrapLogger.class
+ Map<LazyLoggerAccessor, SimpleConsoleLogger> drainTemporaryLoggers() {
+ if (temporaryLoggers.isEmpty()) return null;
+ if (cleared) throw new IllegalStateException("LoggerFinder already initialized");
+ final Map<LazyLoggerAccessor, SimpleConsoleLogger> accessors = new HashMap<>(temporaryLoggers);
+ temporaryLoggers.clear();
+ cleared = true;
+ return accessors;
+ }
+
+ static void resetTemporaryLoggers(Map<LazyLoggerAccessor, SimpleConsoleLogger> accessors) {
+ // When the backend is JUL we want to force the creation of
+ // JUL loggers here: some tests are expecting that the
+ // PlatformLogger will create JUL loggers as soon as the
+ // LogManager is initialized.
+ //
+ // If the backend is not JUL then we can delay the re-creation
+ // of the wrapped logger until they are next accessed.
+ //
+ final LoggingBackend detectedBackend = DetectBackend.detectedBackend;
+ final boolean lazy = detectedBackend != LoggingBackend.JUL_DEFAULT
+ && detectedBackend != LoggingBackend.JUL_WITH_CONFIG;
+ for (Map.Entry<LazyLoggerAccessor, SimpleConsoleLogger> a : accessors.entrySet()) {
+ a.getKey().release(a.getValue(), !lazy);
+ }
+ }
+
+ // all accesses must be synchronized on the outer BootstrapLogger.class
+ static final TemporaryLoggers INSTANCE = new TemporaryLoggers();
+ }
+
+ static synchronized Logger makeTemporaryLogger(LazyLoggerAccessor a) {
+ // accesses to TemporaryLoggers is synchronized on BootstrapLogger.class
+ return TemporaryLoggers.INSTANCE.get(a);
+ }
+
+ private static volatile boolean logManagerConfigured;
+
+ private static synchronized Map<LazyLoggerAccessor, SimpleConsoleLogger>
+ releaseTemporaryLoggers() {
+ // first check whether there's a chance that we have used
+ // temporary loggers; Will be false if logManagerConfigured is already
+ // true.
+ final boolean clearTemporaryLoggers = useTemporaryLoggers();
+
+ // then sets the flag that tells that the log manager is configured
+ logManagerConfigured = true;
+
+ // finally replace all temporary loggers by real JUL loggers
+ if (clearTemporaryLoggers) {
+ // accesses to TemporaryLoggers is synchronized on BootstrapLogger.class
+ return TemporaryLoggers.INSTANCE.drainTemporaryLoggers();
+ } else {
+ return null;
+ }
+ }
+
+ public static void redirectTemporaryLoggers() {
+ // This call is synchronized on BootstrapLogger.class.
+ final Map<LazyLoggerAccessor, SimpleConsoleLogger> accessors =
+ releaseTemporaryLoggers();
+
+ // We will now reset the logger accessors, triggering the
+ // (possibly lazy) replacement of any temporary logger by the
+ // real logger returned from the loaded LoggerFinder.
+ if (accessors != null) {
+ TemporaryLoggers.resetTemporaryLoggers(accessors);
+ }
+
+ BootstrapExecutors.flush();
+ }
+
+ // Hook for tests which need to wait until pending messages
+ // are processed.
+ static void awaitPendingTasks() {
+ BootstrapExecutors.awaitPendingTasks();
+ }
+ static boolean isAlive() {
+ return BootstrapExecutors.isAlive();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/logger/DefaultLoggerFinder.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.logger;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+import java.lang.System.LoggerFinder;
+import java.lang.System.Logger;
+import java.lang.ref.ReferenceQueue;
+import java.util.Collection;
+import java.util.ResourceBundle;
+
+/**
+ * Internal Service Provider Interface (SPI) that makes it possible to use
+ * {@code java.util.logging} as backend when the {@link
+ * sun.util.logging.internal.LoggingProviderImpl
+ * sun.util.logging.internal.LoggingProviderImpl} is present.
+ * <p>
+ * The JDK default implementation of the {@link LoggerFinder} will
+ * attempt to locate and load an {@linkplain
+ * java.util.ServiceLoader#loadInstalled(java.lang.Class) installed}
+ * implementation of the {@code DefaultLoggerFinder}. If {@code java.util.logging}
+ * is present, this will usually resolve to an instance of {@link
+ * sun.util.logging.internal.LoggingProviderImpl sun.util.logging.internal.LoggingProviderImpl}.
+ * Otherwise, if no concrete service provider is declared for
+ * {@code DefaultLoggerFinder}, the default implementation provided by this class
+ * will be used.
+ * <p>
+ * When the {@link sun.util.logging.internal.LoggingProviderImpl
+ * sun.util.logging.internal.LoggingProviderImpl} is not present then the
+ * default implementation provided by this class is to use a simple logger
+ * that will log messages whose level is INFO and above to the console.
+ * These simple loggers are not configurable.
+ * <p>
+ * When configuration is needed, an application should either link with
+ * {@code java.util.logging} - and use the {@code java.util.logging} for
+ * configuration, or link with {@link LoggerFinder another implementation}
+ * of the {@link LoggerFinder}
+ * that provides the necessary configuration.
+ *
+ * @apiNote Programmers are not expected to call this class directly.
+ * Instead they should rely on the static methods defined by {@link
+ * java.lang.System java.lang.System} or {@link sun.util.logging.PlatformLogger
+ * sun.util.logging.PlatformLogger}.
+ *
+ * @see java.lang.System.LoggerFinder
+ * @see jdk.internal.logger
+ * @see sun.util.logging.internal
+ *
+ */
+public class DefaultLoggerFinder extends LoggerFinder {
+
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+
+ /**
+ * Creates a new instance of DefaultLoggerFinder.
+ * @throws SecurityException if the calling code does not have the
+ * {@code RuntimePermission("loggerFinder")}
+ */
+ protected DefaultLoggerFinder() {
+ this(checkPermission());
+ }
+
+ private DefaultLoggerFinder(Void unused) {
+ // nothing to do.
+ }
+
+ private static Void checkPermission() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGERFINDER_PERMISSION);
+ }
+ return null;
+ }
+
+ // SharedLoggers is a default cache of loggers used when JUL is not
+ // present - in that case we use instances of SimpleConsoleLogger which
+ // cannot be directly configure through public APIs.
+ //
+ // We can therefore afford to simply maintain two domains - one for the
+ // system, and one for the application.
+ //
+ static final class SharedLoggers {
+ private final Map<String, Reference<Logger>> loggers =
+ new HashMap<>();
+ private final ReferenceQueue<Logger> queue = new ReferenceQueue<>();
+
+ synchronized Logger get(Function<String, Logger> loggerSupplier, final String name) {
+ Reference<? extends Logger> ref = loggers.get(name);
+ Logger w = ref == null ? null : ref.get();
+ if (w == null) {
+ w = loggerSupplier.apply(name);
+ loggers.put(name, new WeakReference<>(w, queue));
+ }
+
+ // Remove stale mapping...
+ Collection<Reference<Logger>> values = null;
+ while ((ref = queue.poll()) != null) {
+ if (values == null) values = loggers.values();
+ values.remove(ref);
+ }
+ return w;
+ }
+
+
+ final static SharedLoggers system = new SharedLoggers();
+ final static SharedLoggers application = new SharedLoggers();
+ }
+
+ @Override
+ public final Logger getLogger(String name, /* Module */ Class<?> caller) {
+ checkPermission();
+ return demandLoggerFor(name, caller);
+ }
+
+ @Override
+ public final Logger getLocalizedLogger(String name, ResourceBundle bundle,
+ /* Module */ Class<?> caller) {
+ return super.getLocalizedLogger(name, bundle, caller);
+ }
+
+
+
+ /**
+ * Returns a {@link Logger logger} suitable for the caller usage.
+ *
+ * @implSpec The default implementation for this method is to return a
+ * simple logger that will print all messages of INFO level and above
+ * to the console. That simple logger is not configurable.
+ *
+ * @param name The name of the logger.
+ * @param caller The class on behalf of which the logger is created.
+ * @return A {@link Logger logger} suitable for the application usage.
+ * @throws SecurityException if the calling code does not have the
+ * {@code RuntimePermission("loggerFinder")}.
+ */
+ protected Logger demandLoggerFor(String name, /* Module */ Class<?> caller) {
+ checkPermission();
+ if (caller.getClassLoader() == null) {
+ return SharedLoggers.system.get(SimpleConsoleLogger::makeSimpleLogger, name);
+ } else {
+ return SharedLoggers.application.get(SimpleConsoleLogger::makeSimpleLogger, name);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.logger;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.function.BiFunction;
+import java.lang.System.LoggerFinder;
+import java.lang.System.Logger;
+import java.lang.ref.WeakReference;
+import java.util.Objects;
+import sun.misc.VM;
+import sun.util.logging.PlatformLogger;
+
+/**
+ * This class is a factory for Lazy Loggers; only system loggers can be
+ * Lazy Loggers.
+ */
+public final class LazyLoggers {
+
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+
+ private LazyLoggers() {
+ throw new InternalError();
+ }
+
+ /**
+ * This class is used to hold the factories that a Lazy Logger will use
+ * to create (or map) its wrapped logger.
+ * @param <L> {@link Logger} or a subclass of {@link Logger}.
+ */
+ private static final class LazyLoggerFactories<L extends Logger> {
+
+ /**
+ * A factory method to create an SPI logger.
+ * Usually, this will be something like LazyLoggers::getSystemLogger.
+ */
+ final BiFunction<String, Class<?>, L> loggerSupplier;
+
+
+ public LazyLoggerFactories(BiFunction<String, Class<?>, L> loggerSupplier) {
+ this(Objects.requireNonNull(loggerSupplier),
+ (Void)null);
+ }
+
+ private LazyLoggerFactories(BiFunction<String, Class<?>, L> loggerSupplier,
+ Void unused) {
+ this.loggerSupplier = loggerSupplier;
+ }
+
+ }
+
+ static interface LoggerAccessor {
+ /**
+ * The logger name.
+ * @return The name of the logger that is / will be lazily created.
+ */
+ public String getLoggerName();
+
+ /**
+ * Returns the wrapped logger object.
+ * @return the wrapped logger object.
+ */
+ public Logger wrapped();
+
+ /**
+ * A PlatformLogger.Bridge view of the wrapped logger object.
+ * @return A PlatformLogger.Bridge view of the wrapped logger object.
+ */
+ public PlatformLogger.Bridge platform();
+ }
+
+ /**
+ * The LazyLoggerAccessor class holds all the logic that delays the creation
+ * of the SPI logger until such a time that the VM is booted and the logger
+ * is actually used for logging.
+ *
+ * This class uses the services of the BootstrapLogger class to instantiate
+ * temporary loggers if appropriate.
+ */
+ static final class LazyLoggerAccessor implements LoggerAccessor {
+
+ // The factories that will be used to create the logger lazyly
+ final LazyLoggerFactories<? extends Logger> factories;
+
+ // We need to pass the actual caller when creating the logger.
+ private final WeakReference<Class<?>> callerRef;
+
+ // The name of the logger that will be created lazyly
+ final String name;
+ // The plain logger SPI object - null until it is accessed for the
+ // first time.
+ private volatile Logger w;
+ // A PlatformLogger.Bridge view of w.
+ private volatile PlatformLogger.Bridge p;
+
+
+ private LazyLoggerAccessor(String name,
+ LazyLoggerFactories<? extends Logger> factories,
+ Class<?> caller) {
+ this(Objects.requireNonNull(name), Objects.requireNonNull(factories),
+ Objects.requireNonNull(caller), null);
+ }
+
+ private LazyLoggerAccessor(String name,
+ LazyLoggerFactories<? extends Logger> factories,
+ Class<?> caller, Void unused) {
+ this.name = name;
+ this.factories = factories;
+ this.callerRef = new WeakReference<Class<?>>(caller);
+ }
+
+ /**
+ * The logger name.
+ * @return The name of the logger that is / will be lazily created.
+ */
+ @Override
+ public String getLoggerName() {
+ return name;
+ }
+
+ // must be called in synchronized block
+ // set wrapped logger if not set
+ private void setWrappedIfNotSet(Logger wrapped) {
+ if (w == null) {
+ w = wrapped;
+ }
+ }
+
+ /**
+ * Returns the logger SPI object, creating it if 'w' is still null.
+ * @return the logger SPI object.
+ */
+ public Logger wrapped() {
+ Logger wrapped = w;
+ if (wrapped != null) return wrapped;
+ // Wrapped logger not created yet: create it.
+ // BootstrapLogger has the logic to decide whether to invoke the
+ // SPI or use a temporary (BootstrapLogger or SimpleConsoleLogger)
+ // logger.
+ wrapped = BootstrapLogger.getLogger(this);
+ synchronized(this) {
+ // if w has already been in between, simply drop 'wrapped'.
+ setWrappedIfNotSet(wrapped);
+ return w;
+ }
+ }
+
+ /**
+ * A PlatformLogger.Bridge view of the wrapped logger.
+ * @return A PlatformLogger.Bridge view of the wrapped logger.
+ */
+ public PlatformLogger.Bridge platform() {
+ // We can afford to return the platform view of the previous
+ // logger - if that view is not null.
+ // Because that view will either be the BootstrapLogger, which
+ // will redirect to the new wrapper properly, or the temporary
+ // logger - which in effect is equivalent to logging something
+ // just before the application initialized LogManager.
+ PlatformLogger.Bridge platform = p;
+ if (platform != null) return platform;
+ synchronized (this) {
+ if (w != null) {
+ if (p == null) p = PlatformLogger.Bridge.convert(w);
+ return p;
+ }
+ }
+ // If we reach here it means that the wrapped logger may not
+ // have been created yet: attempt to create it.
+ // BootstrapLogger has the logic to decide whether to invoke the
+ // SPI or use a temporary (BootstrapLogger or SimpleConsoleLogger)
+ // logger.
+ final Logger wrapped = BootstrapLogger.getLogger(this);
+ synchronized(this) {
+ // if w has already been set, simply drop 'wrapped'.
+ setWrappedIfNotSet(wrapped);
+ if (p == null) p = PlatformLogger.Bridge.convert(w);
+ return p;
+ }
+ }
+
+ /**
+ * Makes this accessor release a temporary logger.
+ * This method is called
+ * by BootstrapLogger when JUL is the default backend and LogManager
+ * is initialized, in order to replace temporary SimpleConsoleLoggers by
+ * real JUL loggers. See BootstrapLogger for more details.
+ * If {@code replace} is {@code true}, then this method will force
+ * the accessor to eagerly recreate its wrapped logger.
+ * Note: passing {@code replace=false} is no guarantee that the
+ * method will not actually replace the released logger.
+ * @param temporary The temporary logger too be released.
+ * @param replace Whether the released logger should be eagerly
+ * replaced.
+ */
+ void release(SimpleConsoleLogger temporary, boolean replace) {
+ PlatformLogger.ConfigurableBridge.LoggerConfiguration conf =
+ PlatformLogger.ConfigurableBridge.getLoggerConfiguration(temporary);
+ PlatformLogger.Level level = conf != null
+ ? conf.getPlatformLevel()
+ : null;
+ synchronized (this) {
+ if (this.w == temporary) {
+ this.w = null; this.p = null;
+ }
+ }
+ PlatformLogger.Bridge platform = replace || level != null
+ ? this.platform() : null;
+
+ if (level != null) {
+ conf = (platform != null && platform != temporary)
+ ? PlatformLogger.ConfigurableBridge.getLoggerConfiguration(platform)
+ : null;
+ if (conf != null) conf.setPlatformLevel(level);
+ }
+ }
+
+ /**
+ * Replace 'w' by the real SPI logger and flush the log messages pending
+ * in the temporary 'bootstrap' Logger. Called by BootstrapLogger when
+ * this accessor's bootstrap logger is accessed and BootstrapLogger
+ * notices that the VM is no longer booting.
+ * @param bootstrap This accessor's bootstrap logger (usually this is 'w').
+ */
+ Logger getConcreteLogger(BootstrapLogger bootstrap) {
+ assert VM.isBooted();
+ synchronized(this) {
+ // another thread may have already invoked flush()
+ if (this.w == bootstrap) {
+ this.w = null; this.p = null;
+ }
+ }
+ return this.wrapped();
+ }
+
+ PlatformLogger.Bridge getConcretePlatformLogger(BootstrapLogger bootstrap) {
+ assert VM.isBooted();
+ synchronized(this) {
+ // another thread may have already invoked flush()
+ if (this.w == bootstrap) {
+ this.w = null; this.p = null;
+ }
+ }
+ return this.platform();
+ }
+
+ // Creates the wrapped logger by invoking the SPI.
+ Logger createLogger() {
+ final Class<?> caller = callerRef.get();
+ if (caller == null) {
+ throw new IllegalStateException("The class for which this logger"
+ + " was created has been garbage collected");
+ }
+ return this.factories.loggerSupplier.apply(name, caller);
+ }
+
+ /**
+ * Creates a new lazy logger accessor for the named logger. The given
+ * factories will be use when it becomes necessary to actually create
+ * the logger.
+ * @param <T> An interface that extends {@link Logger}.
+ * @param name The logger name.
+ * @param factories The factories that should be used to create the
+ * wrapped logger.
+ * @return A new LazyLoggerAccessor.
+ */
+ public static LazyLoggerAccessor makeAccessor(String name,
+ LazyLoggerFactories<? extends Logger> factories, Class<?> caller) {
+ return new LazyLoggerAccessor(name, factories, caller);
+ }
+
+ }
+
+ /**
+ * An implementation of {@link Logger} that redirects all calls to a wrapped
+ * instance of {@code Logger}.
+ */
+ private static class LazyLoggerWrapper
+ extends AbstractLoggerWrapper<Logger> {
+
+ final LoggerAccessor loggerAccessor;
+
+ public LazyLoggerWrapper(LazyLoggerAccessor loggerSinkSupplier) {
+ this(Objects.requireNonNull(loggerSinkSupplier), (Void)null);
+ }
+
+ private LazyLoggerWrapper(LazyLoggerAccessor loggerSinkSupplier,
+ Void unused) {
+ this.loggerAccessor = loggerSinkSupplier;
+ }
+
+ @Override
+ final Logger wrapped() {
+ return loggerAccessor.wrapped();
+ }
+
+ @Override
+ PlatformLogger.Bridge platformProxy() {
+ return loggerAccessor.platform();
+ }
+
+ }
+
+ // Do not expose this outside of this package.
+ private static volatile LoggerFinder provider = null;
+ private static LoggerFinder accessLoggerFinder() {
+ if (provider == null) {
+ // no need to lock: it doesn't matter if we call
+ // getLoggerFinder() twice - since LoggerFinder already caches
+ // the result.
+ // This is just an optimization to avoid the cost of calling
+ // doPrivileged every time.
+ final SecurityManager sm = System.getSecurityManager();
+ provider = sm == null ? LoggerFinder.getLoggerFinder() :
+ AccessController.doPrivileged(
+ (PrivilegedAction<LoggerFinder>)LoggerFinder::getLoggerFinder);
+ }
+ return provider;
+ }
+
+ // Avoid using lambda here as lazy loggers could be created early
+ // in the bootstrap sequence...
+ private static final BiFunction<String, Class<?>, Logger> loggerSupplier =
+ new BiFunction<>() {
+ @Override
+ public Logger apply(String name, Class<?> caller) {
+ return LazyLoggers.getLoggerFromFinder(name, caller);
+ }
+ };
+
+ private static final LazyLoggerFactories<Logger> factories =
+ new LazyLoggerFactories<>(loggerSupplier);
+
+
+
+ // A concrete implementation of Logger that delegates to a System.Logger,
+ // but only creates the System.Logger instance lazily when it's used for
+ // the first time.
+ // The JdkLazyLogger uses a LazyLoggerAccessor objects, which relies
+ // on the logic embedded in BootstrapLogger to avoid loading the concrete
+ // logger provider until the VM has finished booting.
+ //
+ private static final class JdkLazyLogger extends LazyLoggerWrapper {
+ JdkLazyLogger(String name, Class<?> caller) {
+ this(LazyLoggerAccessor.makeAccessor(name, factories, caller),
+ (Void)null);
+ }
+ private JdkLazyLogger(LazyLoggerAccessor holder, Void unused) {
+ super(holder);
+ }
+ }
+
+ /**
+ * Gets a logger from the LoggerFinder. Creates the actual concrete
+ * logger.
+ * @param name name of the logger
+ * @param caller class on behalf of which the logger is created
+ * @return The logger returned by the LoggerFinder.
+ */
+ static Logger getLoggerFromFinder(String name, Class<?> caller) {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm == null) {
+ return accessLoggerFinder().getLogger(name, caller);
+ } else {
+ return AccessController.doPrivileged((PrivilegedAction<Logger>)
+ () -> {return accessLoggerFinder().getLogger(name, caller);},
+ null, LOGGERFINDER_PERMISSION);
+ }
+ }
+
+ /**
+ * Returns a (possibly lazy) Logger for the caller.
+ *
+ * @param name the logger name
+ * @param caller The class on behalf of which the logger is created.
+ * If the caller is not loaded from the Boot ClassLoader,
+ * the LoggerFinder is accessed and the logger returned
+ * by {@link LoggerFinder#getLogger(java.lang.String, java.lang.Class)}
+ * is returned to the caller directly.
+ * Otherwise, the logger returned by
+ * {@link #getLazyLogger(java.lang.String, java.lang.Class)}
+ * is returned to the caller.
+ *
+ * @return a (possibly lazy) Logger instance.
+ */
+ public static final Logger getLogger(String name, Class<?> caller) {
+ if (caller.getClassLoader() == null) {
+ return getLazyLogger(name, caller);
+ } else {
+ return getLoggerFromFinder(name, caller);
+ }
+ }
+
+ /**
+ * Returns a (possibly lazy) Logger suitable for system classes.
+ * Whether the returned logger is lazy or not depend on the result
+ * returned by {@link BootstrapLogger#useLazyLoggers()}.
+ *
+ * @param name the logger name
+ * @param caller the class on behalf of which the logger is created.
+ * @return a (possibly lazy) Logger instance.
+ */
+ public static final Logger getLazyLogger(String name, Class<?> caller) {
+
+ // BootstrapLogger has the logic to determine whether a LazyLogger
+ // should be used. Usually, it is worth it only if:
+ // - the VM is not yet booted
+ // - or, the backend is JUL and there is no configuration
+ // - or, the backend is a custom backend, as we don't know what
+ // that is going to load...
+ // So if for instance the VM is booted and we use JUL with a custom
+ // configuration, we're not going to delay the creation of loggers...
+ final boolean useLazyLogger = BootstrapLogger.useLazyLoggers();
+ if (useLazyLogger) {
+ return new JdkLazyLogger(name, caller);
+ } else {
+ // Directly invoke the LoggerFinder.
+ return getLoggerFromFinder(name, caller);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/logger/LocalizedLoggerWrapper.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package jdk.internal.logger;
+
+import java.util.ResourceBundle;
+import java.util.function.Supplier;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+
+/**
+ * This implementation of {@link Logger} redirects all logging method
+ * calls to calls to {@code log(Level, String, ResourceBundle, ...)}
+ * methods, passing the Logger's ResourceBundle as parameter.
+ * So for instance a call to {@link Logger#log(Level, String)
+ * log(Level.INFO, msg)} will be redirected
+ * to a call to {@link #log(java.lang.System.Logger.Level,
+ * java.util.ResourceBundle, java.lang.String, java.lang.Object...)
+ * this.log(Level.INFO, this.bundle, msg, (Object[]) null)}.
+ * <p>
+ * Note that methods that take a {@link Supplier Supplier<String>}
+ * or an Object are not redirected. It is assumed that a string returned
+ * by a {@code Supplier<String>} is already localized, or cannot be localized.
+ *
+ * @param <L> Type of the wrapped Logger: {@code Logger} or an
+ * extension of the {@code Logger} interface.
+ */
+public class LocalizedLoggerWrapper<L extends Logger> extends LoggerWrapper<L> {
+
+ private final ResourceBundle bundle;
+
+ public LocalizedLoggerWrapper(L wrapped, ResourceBundle bundle) {
+ super(wrapped);
+ this.bundle = bundle;
+ }
+
+ public final ResourceBundle getBundle() {
+ return bundle;
+ }
+
+ // We assume that messages returned by Supplier<String> and Object are
+ // either already localized or not localizable. To be evaluated.
+
+ // -----------------------------------------------------------------
+ // Generic methods taking a Level as parameter
+ // -----------------------------------------------------------------
+
+ @Override
+ public final void log(Level level, String msg) {
+ log(level, bundle, msg, (Object[]) null);
+ }
+
+ @Override
+ public final void log(Level level,
+ String msg, Throwable thrown) {
+ log(level, bundle, msg, thrown);
+ }
+
+ @Override
+ public final void log(Level level,
+ String format, Object... params) {
+ log(level, bundle, format, params);
+ }
+
+ @Override
+ public final void log(Level level, Object obj) {
+ wrapped.log(level, obj);
+ }
+
+ @Override
+ public final void log(Level level, Supplier<String> msgSupplier) {
+ wrapped.log(level, msgSupplier);
+ }
+
+ @Override
+ public final void log(Level level, Supplier<String> msgSupplier, Throwable thrown) {
+ wrapped.log(level, msgSupplier, thrown);
+ }
+
+ @Override
+ public final void log(Level level, ResourceBundle bundle, String format, Object... params) {
+ wrapped.log(level, bundle, format, params);
+ }
+
+ @Override
+ public final void log(Level level, ResourceBundle bundle, String key, Throwable thrown) {
+ wrapped.log(level, bundle, key, thrown);
+ }
+
+ @Override
+ public final boolean isLoggable(Level level) {
+ return wrapped.isLoggable(level);
+ }
+
+ // Override methods from PlatformLogger.Bridge that don't take a
+ // resource bundle...
+
+ @Override
+ public final void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,
+ String key) {
+ logrb(level, sourceClass, sourceMethod, bundle, key, (Object[]) null);
+ }
+
+ @Override
+ public final void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,
+ String key, Throwable thrown) {
+ logrb(level, sourceClass, sourceMethod, bundle, key, thrown);
+ }
+
+ @Override
+ public final void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,
+ String key, Object... params) {
+ logrb(level, sourceClass, sourceMethod, bundle, key, params);
+ }
+
+ @Override
+ public final void log(sun.util.logging.PlatformLogger.Level level, String msg, Throwable thrown) {
+ logrb(level, bundle, msg, thrown);
+ }
+
+ @Override
+ public final void log(sun.util.logging.PlatformLogger.Level level, String msg) {
+ logrb(level, bundle, msg, (Object[]) null);
+ }
+
+ @Override
+ public final void log(sun.util.logging.PlatformLogger.Level level, String format, Object... params) {
+ logrb(level, bundle, format, params);
+ }
+
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.logger;
+
+import java.io.FilePermission;
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.PrivilegedAction;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
+import sun.security.util.SecurityConstants;
+
+/**
+ * Helper class used to load the {@link java.lang.System.LoggerFinder}.
+ */
+public final class LoggerFinderLoader {
+ private static volatile System.LoggerFinder service;
+ private static final Object lock = new int[0];
+ static final Permission CLASSLOADER_PERMISSION =
+ SecurityConstants.GET_CLASSLOADER_PERMISSION;
+ static final Permission READ_PERMISSION =
+ new FilePermission("<<ALL FILES>>",
+ SecurityConstants.FILE_READ_ACTION);
+ public static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+
+ // This is used to control how the LoggerFinderLoader handles
+ // errors when instantiating the LoggerFinder provider.
+ // ERROR => throws ServiceConfigurationError
+ // WARNING => Do not fail, use plain default (simple logger) implementation,
+ // prints warning on console. (this is the default)
+ // DEBUG => Do not fail, use plain default (simple logger) implementation,
+ // prints warning and exception stack trace on console.
+ // QUIET => Do not fail and stay silent.
+ private static enum ErrorPolicy { ERROR, WARNING, DEBUG, QUIET };
+
+ // This class is static and cannot be instantiated.
+ private LoggerFinderLoader() {
+ throw new InternalError("LoggerFinderLoader cannot be instantiated");
+ }
+
+
+ // Return the loaded LoggerFinder, or load it if not already loaded.
+ private static System.LoggerFinder service() {
+ if (service != null) return service;
+ synchronized(lock) {
+ if (service != null) return service;
+ service = loadLoggerFinder();
+ }
+ // Since the LoggerFinder is already loaded - we can stop using
+ // temporary loggers.
+ BootstrapLogger.redirectTemporaryLoggers();
+ return service;
+ }
+
+ // Get configuration error policy
+ private static ErrorPolicy configurationErrorPolicy() {
+ final PrivilegedAction<String> getConfigurationErrorPolicy =
+ () -> System.getProperty("jdk.logger.finder.error");
+ String errorPolicy = AccessController.doPrivileged(getConfigurationErrorPolicy);
+ if (errorPolicy == null || errorPolicy.isEmpty()) {
+ return ErrorPolicy.WARNING;
+ }
+ try {
+ return ErrorPolicy.valueOf(errorPolicy.toUpperCase(Locale.ROOT));
+ } catch (IllegalArgumentException x) {
+ return ErrorPolicy.WARNING;
+ }
+ }
+
+ // Whether multiple provider should be considered as an error.
+ // This is further submitted to the configuration error policy.
+ private static boolean ensureSingletonProvider() {
+ final PrivilegedAction<Boolean> ensureSingletonProvider =
+ () -> Boolean.getBoolean("jdk.logger.finder.singleton");
+ return AccessController.doPrivileged(ensureSingletonProvider);
+ }
+
+ private static Iterator<System.LoggerFinder> findLoggerFinderProviders() {
+ final Iterator<System.LoggerFinder> iterator;
+ if (System.getSecurityManager() == null) {
+ iterator = ServiceLoader.load(System.LoggerFinder.class,
+ ClassLoader.getSystemClassLoader()).iterator();
+ } else {
+ final PrivilegedAction<Iterator<System.LoggerFinder>> pa =
+ () -> ServiceLoader.load(System.LoggerFinder.class,
+ ClassLoader.getSystemClassLoader()).iterator();
+ iterator = AccessController.doPrivileged(pa, null,
+ LOGGERFINDER_PERMISSION, CLASSLOADER_PERMISSION,
+ READ_PERMISSION);
+ }
+ return iterator;
+ }
+
+ // Loads the LoggerFinder using ServiceLoader. If no LoggerFinder
+ // is found returns the default (possibly JUL based) implementation
+ private static System.LoggerFinder loadLoggerFinder() {
+ System.LoggerFinder result;
+ try {
+ // Iterator iterates with the access control context stored
+ // at ServiceLoader creation time.
+ final Iterator<System.LoggerFinder> iterator =
+ findLoggerFinderProviders();
+ if (iterator.hasNext()) {
+ result = iterator.next();
+ if (iterator.hasNext() && ensureSingletonProvider()) {
+ throw new ServiceConfigurationError(
+ "More than on LoggerFinder implementation");
+ }
+ } else {
+ result = loadDefaultImplementation();
+ }
+ } catch (Error | RuntimeException x) {
+ // next caller will get the plain default impl (not linked
+ // to java.util.logging)
+ service = result = new DefaultLoggerFinder();
+ ErrorPolicy errorPolicy = configurationErrorPolicy();
+ if (errorPolicy == ErrorPolicy.ERROR) {
+ // rethrow any exception as a ServiceConfigurationError.
+ if (x instanceof Error) {
+ throw x;
+ } else {
+ throw new ServiceConfigurationError(
+ "Failed to instantiate LoggerFinder provider; Using default.", x);
+ }
+ } else if (errorPolicy != ErrorPolicy.QUIET) {
+ // if QUIET just silently use the plain default impl
+ // otherwise, log a warning, possibly adding the exception
+ // stack trace (if DEBUG is specified).
+ SimpleConsoleLogger logger =
+ new SimpleConsoleLogger("jdk.internal.logger", false);
+ logger.log(System.Logger.Level.WARNING,
+ "Failed to instantiate LoggerFinder provider; Using default.");
+ if (errorPolicy == ErrorPolicy.DEBUG) {
+ logger.log(System.Logger.Level.WARNING,
+ "Exception raised trying to instantiate LoggerFinder", x);
+ }
+ }
+ }
+ return result;
+ }
+
+ private static System.LoggerFinder loadDefaultImplementation() {
+ final SecurityManager sm = System.getSecurityManager();
+ final Iterator<DefaultLoggerFinder> iterator;
+ if (sm == null) {
+ iterator = ServiceLoader.loadInstalled(DefaultLoggerFinder.class).iterator();
+ } else {
+ // We use limited do privileged here - the minimum set of
+ // permissions required to 'see' the META-INF/services resources
+ // seems to be CLASSLOADER_PERMISSION and READ_PERMISSION.
+ // Note that do privileged is required because
+ // otherwise the SecurityManager will prevent the ServiceLoader
+ // from seeing the installed provider.
+ PrivilegedAction<Iterator<DefaultLoggerFinder>> pa = () ->
+ ServiceLoader.loadInstalled(DefaultLoggerFinder.class).iterator();
+ iterator = AccessController.doPrivileged(pa, null,
+ LOGGERFINDER_PERMISSION, CLASSLOADER_PERMISSION,
+ READ_PERMISSION);
+ }
+ DefaultLoggerFinder result = null;
+ try {
+ // Iterator iterates with the access control context stored
+ // at ServiceLoader creation time.
+ if (iterator.hasNext()) {
+ result = iterator.next();
+ }
+ } catch (RuntimeException x) {
+ throw new ServiceConfigurationError(
+ "Failed to instantiate default LoggerFinder", x);
+ }
+ if (result == null) {
+ result = new DefaultLoggerFinder();
+ }
+ return result;
+ }
+
+ public static System.LoggerFinder getLoggerFinder() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGERFINDER_PERMISSION);
+ }
+ return service();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/logger/LoggerWrapper.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package jdk.internal.logger;
+
+import java.util.Objects;
+import java.lang.System.Logger;
+import sun.util.logging.PlatformLogger;
+
+/**
+ * An implementation of {@link Logger} that redirects all calls to a wrapped
+ instance of Logger.
+ *
+ * @param <L> Type of the wrapped Logger: {@code Logger} or an
+ * extension of that interface.
+ */
+public class LoggerWrapper<L extends Logger> extends AbstractLoggerWrapper<L> {
+
+ final L wrapped;
+ final PlatformLogger.Bridge platformProxy;
+
+ public LoggerWrapper(L wrapped) {
+ this(Objects.requireNonNull(wrapped), (Void)null);
+ }
+
+ LoggerWrapper(L wrapped, Void unused) {
+ this.wrapped = wrapped;
+ this.platformProxy = (wrapped instanceof PlatformLogger.Bridge) ?
+ (PlatformLogger.Bridge) wrapped : null;
+ }
+
+ @Override
+ public final L wrapped() {
+ return wrapped;
+ }
+
+ @Override
+ public final PlatformLogger.Bridge platformProxy() {
+ return platformProxy;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/logger/SimpleConsoleLogger.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.logger;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.time.ZonedDateTime;
+import java.util.ResourceBundle;
+import java.util.function.Function;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.util.function.Supplier;
+import jdk.internal.misc.JavaLangAccess;
+import jdk.internal.misc.SharedSecrets;
+import sun.util.logging.PlatformLogger;
+import sun.util.logging.PlatformLogger.ConfigurableBridge.LoggerConfiguration;
+
+/**
+ * A simple console logger to emulate the behavior of JUL loggers when
+ * in the default configuration. SimpleConsoleLoggers are also used when
+ * JUL is not present and no DefaultLoggerFinder is installed.
+ */
+public class SimpleConsoleLogger extends LoggerConfiguration
+ implements Logger, PlatformLogger.Bridge, PlatformLogger.ConfigurableBridge {
+
+ static final PlatformLogger.Level DEFAULT_LEVEL = PlatformLogger.Level.INFO;
+
+ final String name;
+ volatile PlatformLogger.Level level;
+ final boolean usePlatformLevel;
+ SimpleConsoleLogger(String name, boolean usePlatformLevel) {
+ this.name = name;
+ this.usePlatformLevel = usePlatformLevel;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ private Enum<?> logLevel(PlatformLogger.Level level) {
+ return usePlatformLevel ? level : level.systemLevel();
+ }
+
+ private Enum<?> logLevel(Level level) {
+ return usePlatformLevel ? PlatformLogger.toPlatformLevel(level) : level;
+ }
+
+ // ---------------------------------------------------
+ // From Logger
+ // ---------------------------------------------------
+
+ @Override
+ public boolean isLoggable(Level level) {
+ return isLoggable(PlatformLogger.toPlatformLevel(level));
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle, String key, Throwable thrown) {
+ if (isLoggable(level)) {
+ if (bundle != null) {
+ key = bundle.getString(key);
+ }
+ publish(getCallerInfo(), logLevel(level), key, thrown);
+ }
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle, String format, Object... params) {
+ if (isLoggable(level)) {
+ if (bundle != null) {
+ format = bundle.getString(format);
+ }
+ publish(getCallerInfo(), logLevel(level), format, params);
+ }
+ }
+
+ // ---------------------------------------------------
+ // From PlatformLogger.Bridge
+ // ---------------------------------------------------
+
+ @Override
+ public boolean isLoggable(PlatformLogger.Level level) {
+ final PlatformLogger.Level effectiveLevel = effectiveLevel();
+ return level != PlatformLogger.Level.OFF
+ && level.ordinal() >= effectiveLevel.ordinal();
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return level != PlatformLogger.Level.OFF;
+ }
+
+ @Override
+ public void log(PlatformLogger.Level level, String msg) {
+ if (isLoggable(level)) {
+ publish(getCallerInfo(), logLevel(level), msg);
+ }
+ }
+
+ @Override
+ public void log(PlatformLogger.Level level, String msg, Throwable thrown) {
+ if (isLoggable(level)) {
+ publish(getCallerInfo(), logLevel(level), msg, thrown);
+ }
+ }
+
+ @Override
+ public void log(PlatformLogger.Level level, String msg, Object... params) {
+ if (isLoggable(level)) {
+ publish(getCallerInfo(), logLevel(level), msg, params);
+ }
+ }
+
+ private PlatformLogger.Level effectiveLevel() {
+ if (level == null) return DEFAULT_LEVEL;
+ return level;
+ }
+
+ @Override
+ public PlatformLogger.Level getPlatformLevel() {
+ return level;
+ }
+
+ @Override
+ public void setPlatformLevel(PlatformLogger.Level newLevel) {
+ level = newLevel;
+ }
+
+ @Override
+ public LoggerConfiguration getLoggerConfiguration() {
+ return this;
+ }
+
+ /**
+ * Default platform logging support - output messages to System.err -
+ * equivalent to ConsoleHandler with SimpleFormatter.
+ */
+ static PrintStream outputStream() {
+ return System.err;
+ }
+
+ // Returns the caller's class and method's name; best effort
+ // if cannot infer, return the logger's name.
+ private String getCallerInfo() {
+ String sourceClassName = null;
+ String sourceMethodName = null;
+
+ JavaLangAccess access = SharedSecrets.getJavaLangAccess();
+ Throwable throwable = new Throwable();
+ int depth = access.getStackTraceDepth(throwable);
+
+ String logClassName = "sun.util.logging.PlatformLogger";
+ String simpleLoggerClassName = "jdk.internal.logger.SimpleConsoleLogger";
+ boolean lookingForLogger = true;
+ for (int ix = 0; ix < depth; ix++) {
+ // Calling getStackTraceElement directly prevents the VM
+ // from paying the cost of building the entire stack frame.
+ final StackTraceElement frame =
+ access.getStackTraceElement(throwable, ix);
+ final String cname = frame.getClassName();
+ if (lookingForLogger) {
+ // Skip all frames until we have found the first logger frame.
+ if (cname.equals(logClassName) || cname.equals(simpleLoggerClassName)) {
+ lookingForLogger = false;
+ }
+ } else {
+ if (skipLoggingFrame(cname)) continue;
+ if (!cname.equals(logClassName) && !cname.equals(simpleLoggerClassName)) {
+ // We've found the relevant frame.
+ sourceClassName = cname;
+ sourceMethodName = frame.getMethodName();
+ break;
+ }
+ }
+ }
+
+ if (sourceClassName != null) {
+ return sourceClassName + " " + sourceMethodName;
+ } else {
+ return name;
+ }
+ }
+
+ private String getCallerInfo(String sourceClassName, String sourceMethodName) {
+ if (sourceClassName == null) return name;
+ if (sourceMethodName == null) return sourceClassName;
+ return sourceClassName + " " + sourceMethodName;
+ }
+
+ private String toString(Throwable thrown) {
+ String throwable = "";
+ if (thrown != null) {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ pw.println();
+ thrown.printStackTrace(pw);
+ pw.close();
+ throwable = sw.toString();
+ }
+ return throwable;
+ }
+
+ private synchronized String format(Enum<?> level,
+ String msg, Throwable thrown, String callerInfo) {
+
+ ZonedDateTime zdt = ZonedDateTime.now();
+ String throwable = toString(thrown);
+
+ return String.format(Formatting.formatString,
+ zdt,
+ callerInfo,
+ name,
+ level.name(),
+ msg,
+ throwable);
+ }
+
+ // publish accepts both PlatformLogger Levels and LoggerFinder Levels.
+ private void publish(String callerInfo, Enum<?> level, String msg) {
+ outputStream().print(format(level, msg, null, callerInfo));
+ }
+ // publish accepts both PlatformLogger Levels and LoggerFinder Levels.
+ private void publish(String callerInfo, Enum<?> level, String msg, Throwable thrown) {
+ outputStream().print(format(level, msg, thrown, callerInfo));
+ }
+ // publish accepts both PlatformLogger Levels and LoggerFinder Levels.
+ private void publish(String callerInfo, Enum<?> level, String msg, Object... params) {
+ msg = params == null || params.length == 0 ? msg
+ : Formatting.formatMessage(msg, params);
+ outputStream().print(format(level, msg, null, callerInfo));
+ }
+
+ public static SimpleConsoleLogger makeSimpleLogger(String name, boolean usePlatformLevel) {
+ return new SimpleConsoleLogger(name, usePlatformLevel);
+ }
+
+ public static SimpleConsoleLogger makeSimpleLogger(String name) {
+ return new SimpleConsoleLogger(name, false);
+ }
+
+ public static String getSimpleFormat(Function<String, String> defaultPropertyGetter) {
+ return Formatting.getSimpleFormat(defaultPropertyGetter);
+ }
+
+ public static boolean skipLoggingFrame(String cname) {
+ return Formatting.skipLoggingFrame(cname);
+ }
+
+ @Override
+ public void log(PlatformLogger.Level level, Supplier<String> msgSupplier) {
+ if (isLoggable(level)) {
+ publish(getCallerInfo(), logLevel(level), msgSupplier.get());
+ }
+ }
+
+ @Override
+ public void log(PlatformLogger.Level level, Throwable thrown,
+ Supplier<String> msgSupplier) {
+ if (isLoggable(level)) {
+ publish(getCallerInfo(), logLevel(level), msgSupplier.get(), thrown);
+ }
+ }
+
+ @Override
+ public void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, String msg) {
+ if (isLoggable(level)) {
+ publish(getCallerInfo(sourceClass, sourceMethod), logLevel(level), msg);
+ }
+ }
+
+ @Override
+ public void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, Supplier<String> msgSupplier) {
+ if (isLoggable(level)) {
+ publish(getCallerInfo(sourceClass, sourceMethod), logLevel(level), msgSupplier.get());
+ }
+ }
+
+ @Override
+ public void logp(PlatformLogger.Level level, String sourceClass, String sourceMethod,
+ String msg, Object... params) {
+ if (isLoggable(level)) {
+ publish(getCallerInfo(sourceClass, sourceMethod), logLevel(level), msg, params);
+ }
+ }
+
+ @Override
+ public void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, String msg, Throwable thrown) {
+ if (isLoggable(level)) {
+ publish(getCallerInfo(sourceClass, sourceMethod), logLevel(level), msg, thrown);
+ }
+ }
+
+ @Override
+ public void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, Throwable thrown, Supplier<String> msgSupplier) {
+ if (isLoggable(level)) {
+ publish(getCallerInfo(sourceClass, sourceMethod), logLevel(level), msgSupplier.get(), thrown);
+ }
+ }
+
+ @Override
+ public void logrb(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, ResourceBundle bundle, String key, Object... params) {
+ if (isLoggable(level)) {
+ String msg = bundle == null ? key : bundle.getString(key);
+ publish(getCallerInfo(sourceClass, sourceMethod), logLevel(level), msg, params);
+ }
+ }
+
+ @Override
+ public void logrb(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, ResourceBundle bundle, String key, Throwable thrown) {
+ if (isLoggable(level)) {
+ String msg = bundle == null ? key : bundle.getString(key);
+ publish(getCallerInfo(sourceClass, sourceMethod), logLevel(level), msg, thrown);
+ }
+ }
+
+ @Override
+ public void logrb(PlatformLogger.Level level, ResourceBundle bundle,
+ String key, Object... params) {
+ if (isLoggable(level)) {
+ String msg = bundle == null ? key : bundle.getString(key);
+ publish(getCallerInfo(), logLevel(level), msg, params);
+ }
+ }
+
+ @Override
+ public void logrb(PlatformLogger.Level level, ResourceBundle bundle,
+ String key, Throwable thrown) {
+ if (isLoggable(level)) {
+ String msg = bundle == null ? key : bundle.getString(key);
+ publish(getCallerInfo(), logLevel(level), msg, thrown);
+ }
+ }
+
+ private static final class Formatting {
+ static final String DEFAULT_FORMAT =
+ "%1$tb %1$td, %1$tY %1$tl:%1$tM:%1$tS %1$Tp %2$s%n%4$s: %5$s%6$s%n";
+ static final String FORMAT_PROP_KEY =
+ "java.util.logging.SimpleFormatter.format";
+ static final String formatString = getSimpleFormat(null);
+
+ // Make it easier to wrap Logger...
+ static private final String[] skips;
+ static {
+ String additionalPkgs = AccessController.doPrivileged(
+ (PrivilegedAction<String>)
+ () -> System.getProperty("jdk.logger.packages"));
+ skips = additionalPkgs == null ? new String[0] : additionalPkgs.split(",");
+
+ }
+
+ static boolean skipLoggingFrame(String cname) {
+ // skip logging/logger infrastructure
+
+ // fast escape path: all the prefixes below start with 's' or 'j' and
+ // have more than 12 characters.
+ char c = cname.length() < 12 ? 0 : cname.charAt(0);
+ if (c == 's') {
+ // skip internal machinery classes
+ if (cname.startsWith("sun.util.logging.")) return true;
+ if (cname.startsWith("sun.reflect.")) return true;
+ if (cname.startsWith("sun.rmi.runtime.Log")) return true;
+ } else if (c == 'j') {
+ // Message delayed at Bootstrap: no need to go further up.
+ if (cname.startsWith("jdk.internal.logger.BootstrapLogger$LogEvent")) return false;
+ // skip public machinery classes
+ if (cname.startsWith("jdk.internal.logger.")) return true;
+ if (cname.startsWith("java.util.logging.")) return true;
+ if (cname.startsWith("java.lang.System$Logger")) return true;
+ if (cname.startsWith("java.lang.reflect.")) return true;
+ if (cname.startsWith("java.lang.invoke.MethodHandle")) return true;
+ if (cname.startsWith("java.lang.invoke.LambdaForm")) return true;
+ if (cname.startsWith("java.security.AccessController")) return true;
+ }
+
+ // check additional prefixes if any are specified.
+ if (skips.length > 0) {
+ for (int i=0; i<skips.length; i++) {
+ if (!skips[i].isEmpty() && cname.startsWith(skips[i])) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ static String getSimpleFormat(Function<String, String> defaultPropertyGetter) {
+ // Using a lambda here causes
+ // jdk/test/java/lang/invoke/lambda/LogGeneratedClassesTest.java
+ // to fail - because that test has a testcase which somehow references
+ // PlatformLogger and counts the number of generated lambda classes
+ // So we explicitely use new PrivilegedAction<String> here.
+ String format =
+ AccessController.doPrivileged(new PrivilegedAction<String>() {
+ @Override
+ public String run() {
+ return System.getProperty(FORMAT_PROP_KEY);
+ }
+ });
+ if (format == null && defaultPropertyGetter != null) {
+ format = defaultPropertyGetter.apply(FORMAT_PROP_KEY);
+ }
+ if (format != null) {
+ try {
+ // validate the user-defined format string
+ String.format(format, ZonedDateTime.now(), "", "", "", "", "");
+ } catch (IllegalArgumentException e) {
+ // illegal syntax; fall back to the default format
+ format = DEFAULT_FORMAT;
+ }
+ } else {
+ format = DEFAULT_FORMAT;
+ }
+ return format;
+ }
+
+
+ // Copied from java.util.logging.Formatter.formatMessage
+ static String formatMessage(String format, Object... parameters) {
+ // Do the formatting.
+ try {
+ if (parameters == null || parameters.length == 0) {
+ // No parameters. Just return format string.
+ return format;
+ }
+ // Is it a java.text style format?
+ // Ideally we could match with
+ // Pattern.compile("\\{\\d").matcher(format).find())
+ // However the cost is 14% higher, so we cheaply check for
+ //
+ boolean isJavaTestFormat = false;
+ final int len = format.length();
+ for (int i=0; i<len-2; i++) {
+ final char c = format.charAt(i);
+ if (c == '{') {
+ final int d = format.charAt(i+1);
+ if (d >= '0' && d <= '9') {
+ isJavaTestFormat = true;
+ break;
+ }
+ }
+ }
+ if (isJavaTestFormat) {
+ return java.text.MessageFormat.format(format, parameters);
+ }
+ return format;
+ } catch (Exception ex) {
+ // Formatting failed: use format string.
+ return format;
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/logger/package-info.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * <b>[JDK INTERNAL]</b>
+ * The {@code jdk.internal.logger} package defines an internal provider
+ * whose default naive implementation is replaced by the {@code java.logging}
+ * module when the {@code java.logging} module is present.
+ * <p>
+ * <b>Default Implementation</b>
+ * <p>
+ * The JDK default implementation of the System.LoggerFinder will attempt to
+ * load an installed instance of the {@link jdk.internal.logger.DefaultLoggerFinder}
+ * defined in this package.
+ * When the {@code java.util.logging} package is present, this will usually
+ * resolve to an instance of {@link sun.util.logging.internal.LoggingProviderImpl} -
+ * which provides an implementation of the Logger whose backend is a
+ * {@link java.util.logging.Logger java.util.logging.Logger}.
+ * Configuration can thus be performed by direct access to the regular
+ * {@code java.util.logging} APIs,
+ * using {@link java.util.logging.Logger java.util.logging.Logger} and
+ * {@link java.util.logging.LogManager} to access and configure the backend
+ * Loggers.
+ * <br>
+ * If however {@code java.util.logging} is not linked with the application, then
+ * the default implementation will return a simple logger that will print out
+ * all log messages of INFO level and above to the console ({@code System.err}),
+ * as implemented by the base {@link jdk.internal.logger.DefaultLoggerFinder} class.
+ * <p>
+ * <b>Message Levels and Mapping to java.util.logging</b>
+ * <p>
+ * The {@link java.lang.System.LoggerFinder} class documentation describe how
+ * {@linkplain java.lang.System.Logger.Level System.Logger levels} are mapped
+ * to {@linkplain java.util.logging.Level JUL levels} when {@code
+ * java.util.logging} is the backend.
+ *
+ * @see jdk.internal.logger.DefaultLoggerFinder
+ * @see sun.util.logging.internal.LoggingProviderImpl
+ * @see java.lang.System.LoggerFinder
+ * @see java.lang.System.Logger
+ * @see sun.util.logging.PlatformLogger.Bridge
+ * @see sun.util.logging.internal
+ *
+ * @since 1.9
+ */
+package jdk.internal.logger;
--- a/jdk/src/java.base/share/classes/sun/invoke/util/Wrapper.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/invoke/util/Wrapper.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,36 +26,34 @@
package sun.invoke.util;
public enum Wrapper {
- // wrapperType primitiveType char zero emptyArray format
- BOOLEAN( Boolean.class, boolean.class, 'Z', Boolean.FALSE, new boolean[0], Format.unsigned( 1)),
+ // wrapperType primitiveType char emptyArray format
+ BOOLEAN( Boolean.class, boolean.class, 'Z', new boolean[0], Format.unsigned( 1)),
// These must be in the order defined for widening primitive conversions in JLS 5.1.2
// Avoid boxing integral types here to defer initialization of internal caches
- BYTE ( Byte.class, byte.class, 'B', new Byte((byte)0), new byte[0], Format.signed( 8)),
- SHORT ( Short.class, short.class, 'S', new Short((short)0), new short[0], Format.signed( 16)),
- CHAR (Character.class, char.class, 'C', new Character((char)0), new char[0], Format.unsigned(16)),
- INT ( Integer.class, int.class, 'I', new Integer(0), new int[0], Format.signed( 32)),
- LONG ( Long.class, long.class, 'J', new Long(0), new long[0], Format.signed( 64)),
- FLOAT ( Float.class, float.class, 'F', (Float)(float)0, new float[0], Format.floating(32)),
- DOUBLE ( Double.class, double.class, 'D', (Double)(double)0, new double[0], Format.floating(64)),
- OBJECT ( Object.class, Object.class, 'L', null, new Object[0], Format.other( 1)),
+ BYTE ( Byte.class, byte.class, 'B', new byte[0], Format.signed( 8)),
+ SHORT ( Short.class, short.class, 'S', new short[0], Format.signed( 16)),
+ CHAR (Character.class, char.class, 'C', new char[0], Format.unsigned(16)),
+ INT ( Integer.class, int.class, 'I', new int[0], Format.signed( 32)),
+ LONG ( Long.class, long.class, 'J', new long[0], Format.signed( 64)),
+ FLOAT ( Float.class, float.class, 'F', new float[0], Format.floating(32)),
+ DOUBLE ( Double.class, double.class, 'D', new double[0], Format.floating(64)),
+ OBJECT ( Object.class, Object.class, 'L', new Object[0], Format.other( 1)),
// VOID must be the last type, since it is "assignable" from any other type:
- VOID ( Void.class, void.class, 'V', null, null, Format.other( 0)),
+ VOID ( Void.class, void.class, 'V', null, Format.other( 0)),
;
private final Class<?> wrapperType;
private final Class<?> primitiveType;
private final char basicTypeChar;
- private final Object zero;
private final Object emptyArray;
private final int format;
private final String wrapperSimpleName;
private final String primitiveSimpleName;
- private Wrapper(Class<?> wtype, Class<?> ptype, char tchar, Object zero, Object emptyArray, int format) {
+ private Wrapper(Class<?> wtype, Class<?> ptype, char tchar, Object emptyArray, int format) {
this.wrapperType = wtype;
this.primitiveType = ptype;
this.basicTypeChar = tchar;
- this.zero = zero;
this.emptyArray = emptyArray;
this.format = format;
this.wrapperSimpleName = wtype.getSimpleName();
@@ -66,7 +64,7 @@
public String detailString() {
return wrapperSimpleName+
java.util.Arrays.asList(wrapperType, primitiveType,
- basicTypeChar, zero,
+ basicTypeChar, zero(),
"0x"+Integer.toHexString(format));
}
@@ -223,13 +221,39 @@
* type. (For void, it is what a reflective method returns
* instead of no value at all.)
*/
- public Object zero() { return zero; }
+ public Object zero() {
+ switch (this) {
+ case BOOLEAN:
+ return Boolean.FALSE;
+ case INT:
+ return (Integer)0;
+ case BYTE:
+ return (Byte)(byte)0;
+ case CHAR:
+ return (Character)(char)0;
+ case SHORT:
+ return (Short)(short)0;
+ case LONG:
+ return (Long)(long)0;
+ case FLOAT:
+ return FLOAT_ZERO;
+ case DOUBLE:
+ return DOUBLE_ZERO;
+ case VOID:
+ case OBJECT:
+ default:
+ return null;
+ }
+ }
+
+ private static final Object DOUBLE_ZERO = (Double)(double)0;
+ private static final Object FLOAT_ZERO = (Float)(float)0;
/** Produce a zero value for the given wrapper type T.
* The optional argument must a type compatible with this wrapper.
* Equivalent to {@code this.cast(this.zero(), type)}.
*/
- public <T> T zero(Class<T> type) { return convert(zero, type); }
+ public <T> T zero(Class<T> type) { return convert(zero(), type); }
/** Return the wrapper that wraps values of the given type.
* The type may be {@code Object}, meaning the {@code OBJECT} wrapper.
@@ -474,7 +498,7 @@
}
} else if (x == null) {
@SuppressWarnings("unchecked")
- T z = (T) zero;
+ T z = (T) zero();
return z;
}
@SuppressWarnings("unchecked")
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/AdaptableX509CertSelector.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/AdaptableX509CertSelector.java Wed Jul 05 21:02:29 2017 +0200
@@ -36,9 +36,7 @@
import sun.security.util.Debug;
import sun.security.util.DerInputStream;
-import sun.security.util.DerOutputStream;
import sun.security.x509.SerialNumber;
-import sun.security.x509.KeyIdentifier;
import sun.security.x509.AuthorityKeyIdentifierExtension;
/**
@@ -131,13 +129,7 @@
serial = null;
if (ext != null) {
- KeyIdentifier akid = (KeyIdentifier)ext.get(
- AuthorityKeyIdentifierExtension.KEY_ID);
- if (akid != null) {
- DerOutputStream derout = new DerOutputStream();
- derout.putOctetString(akid.getIdentifier());
- ski = derout.toByteArray();
- }
+ ski = ext.getEncodedKeyIdentifier();
SerialNumber asn = (SerialNumber)ext.get(
AuthorityKeyIdentifierExtension.SERIAL_NUMBER);
if (asn != null) {
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java Wed Jul 05 21:02:29 2017 +0200
@@ -33,7 +33,6 @@
import java.util.*;
import sun.security.util.Debug;
-import sun.security.util.DerOutputStream;
import static sun.security.x509.PKIXExtensions.*;
import sun.security.x509.*;
@@ -607,12 +606,9 @@
AuthorityKeyIdentifierExtension akidext =
crlImpl.getAuthKeyIdExtension();
if (akidext != null) {
- KeyIdentifier akid = (KeyIdentifier)akidext.get(
- AuthorityKeyIdentifierExtension.KEY_ID);
- if (akid != null) {
- DerOutputStream derout = new DerOutputStream();
- derout.putOctetString(akid.getIdentifier());
- certSel.setSubjectKeyIdentifier(derout.toByteArray());
+ byte[] kid = akidext.getEncodedKeyIdentifier();
+ if (kid != null) {
+ certSel.setSubjectKeyIdentifier(kid);
}
SerialNumber asn = (SerialNumber)akidext.get(
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java Wed Jul 05 21:02:29 2017 +0200
@@ -46,9 +46,10 @@
import sun.security.util.Debug;
import sun.security.x509.AccessDescription;
import sun.security.x509.AuthorityInfoAccessExtension;
+import sun.security.x509.AuthorityKeyIdentifierExtension;
import static sun.security.x509.PKIXExtensions.*;
import sun.security.x509.X500Name;
-import sun.security.x509.AuthorityKeyIdentifierExtension;
+import sun.security.x509.X509CertImpl;
/**
* This class represents a forward builder, which is able to retrieve
@@ -69,7 +70,6 @@
private AdaptableX509CertSelector caSelector;
private X509CertSelector caTargetSelector;
TrustAnchor trustAnchor;
- private Comparator<X509Certificate> comparator;
private boolean searchAllCertStores = true;
/**
@@ -93,7 +93,6 @@
trustedSubjectDNs.add(anchor.getCA());
}
}
- comparator = new PKIXCertComparator(trustedSubjectDNs);
this.searchAllCertStores = searchAllCertStores;
}
@@ -122,6 +121,8 @@
* As each cert is added, it is sorted based on the PKIXCertComparator
* algorithm.
*/
+ Comparator<X509Certificate> comparator =
+ new PKIXCertComparator(trustedSubjectDNs, currState.cert);
Set<X509Certificate> certs = new TreeSet<>(comparator);
/*
@@ -265,14 +266,6 @@
(caSelector, currentState.subjectNamesTraversed);
/*
- * Facilitate certification path construction with authority
- * key identifier and subject key identifier.
- */
- AuthorityKeyIdentifierExtension akidext =
- currentState.cert.getAuthorityKeyIdentifierExtension();
- caSelector.setSkiAndSerialNumber(akidext);
-
- /*
* check the validity period
*/
caSelector.setValidityPeriod(currentState.cert.getNotBefore(),
@@ -404,41 +397,68 @@
*
* Preference order for current cert:
*
- * 1) Issuer matches a trusted subject
+ * 1) The key identifier of an AKID extension (if present) in the
+ * previous certificate matches the key identifier in the SKID extension
+ *
+ * 2) Issuer matches a trusted subject
* Issuer: ou=D,ou=C,o=B,c=A
*
- * 2) Issuer is a descendant of a trusted subject (in order of
+ * 3) Issuer is a descendant of a trusted subject (in order of
* number of links to the trusted subject)
* a) Issuer: ou=E,ou=D,ou=C,o=B,c=A [links=1]
* b) Issuer: ou=F,ou=E,ou=D,ou=C,ou=B,c=A [links=2]
*
- * 3) Issuer is an ancestor of a trusted subject (in order of number of
+ * 4) Issuer is an ancestor of a trusted subject (in order of number of
* links to the trusted subject)
* a) Issuer: ou=C,o=B,c=A [links=1]
* b) Issuer: o=B,c=A [links=2]
*
- * 4) Issuer is in the same namespace as a trusted subject (in order of
+ * 5) Issuer is in the same namespace as a trusted subject (in order of
* number of links to the trusted subject)
* a) Issuer: ou=G,ou=C,o=B,c=A [links=2]
* b) Issuer: ou=H,o=B,c=A [links=3]
*
- * 5) Issuer is an ancestor of certificate subject (in order of number
+ * 6) Issuer is an ancestor of certificate subject (in order of number
* of links to the certificate subject)
* a) Issuer: ou=K,o=J,c=A
* Subject: ou=L,ou=K,o=J,c=A
* b) Issuer: o=J,c=A
* Subject: ou=L,ou=K,0=J,c=A
*
- * 6) Any other certificates
+ * 7) Any other certificates
*/
static class PKIXCertComparator implements Comparator<X509Certificate> {
static final String METHOD_NME = "PKIXCertComparator.compare()";
private final Set<X500Principal> trustedSubjectDNs;
+ private final X509CertSelector certSkidSelector;
- PKIXCertComparator(Set<X500Principal> trustedSubjectDNs) {
+ PKIXCertComparator(Set<X500Principal> trustedSubjectDNs,
+ X509CertImpl previousCert) throws IOException {
this.trustedSubjectDNs = trustedSubjectDNs;
+ this.certSkidSelector = getSelector(previousCert);
+ }
+
+ /**
+ * Returns an X509CertSelector for matching on the authority key
+ * identifier, or null if not applicable.
+ */
+ private X509CertSelector getSelector(X509CertImpl previousCert)
+ throws IOException {
+ if (previousCert != null) {
+ AuthorityKeyIdentifierExtension akidExt =
+ previousCert.getAuthorityKeyIdentifierExtension();
+ if (akidExt != null) {
+ byte[] skid = akidExt.getEncodedKeyIdentifier();
+ if (skid != null) {
+ X509CertSelector selector = new X509CertSelector();
+ selector.setSubjectKeyIdentifier(skid);
+ return selector;
+ }
+ }
+ }
+ return null;
}
/**
@@ -462,6 +482,16 @@
// if certs are the same, return 0
if (oCert1.equals(oCert2)) return 0;
+ // If akid/skid match then it is preferable
+ if (certSkidSelector != null) {
+ if (certSkidSelector.match(oCert1)) {
+ return -1;
+ }
+ if (certSkidSelector.match(oCert2)) {
+ return 1;
+ }
+ }
+
X500Principal cIssuer1 = oCert1.getIssuerX500Principal();
X500Principal cIssuer2 = oCert2.getIssuerX500Principal();
X500Name cIssuer1Name = X500Name.asX500Name(cIssuer1);
--- a/jdk/src/java.base/share/classes/sun/security/x509/AlgorithmId.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/security/x509/AlgorithmId.java Wed Jul 05 21:02:29 2017 +0200
@@ -977,4 +977,69 @@
}
return null;
}
+
+ /**
+ * Checks if a signature algorithm matches a key algorithm, i.e. a
+ * signature can be initialized with a key.
+ *
+ * @param kAlg must not be null
+ * @param sAlg must not be null
+ * @throws IllegalArgumentException if they do not match
+ */
+ public static void checkKeyAndSigAlgMatch(String kAlg, String sAlg) {
+ String sAlgUp = sAlg.toUpperCase(Locale.US);
+ if ((sAlgUp.endsWith("WITHRSA") && !kAlg.equalsIgnoreCase("RSA")) ||
+ (sAlgUp.endsWith("WITHECDSA") && !kAlg.equalsIgnoreCase("EC")) ||
+ (sAlgUp.endsWith("WITHDSA") && !kAlg.equalsIgnoreCase("DSA"))) {
+ throw new IllegalArgumentException(
+ "key algorithm not compatible with signature algorithm");
+ }
+ }
+
+ /**
+ * Returns the default signature algorithm for a private key. The digest
+ * part might evolve with time. Remember to update the spec of
+ * {@link jdk.security.jarsigner.JarSigner.Builder#getDefaultSignatureAlgorithm(PrivateKey)}
+ * if updated.
+ *
+ * @param k cannot be null
+ * @return the default alg, might be null if unsupported
+ */
+ public static String getDefaultSigAlgForKey(PrivateKey k) {
+ switch (k.getAlgorithm().toUpperCase()) {
+ case "EC":
+ return ecStrength(KeyUtil.getKeySize(k))
+ + "withECDSA";
+ case "DSA":
+ return ifcFfcStrength(KeyUtil.getKeySize(k))
+ + "withDSA";
+ case "RSA":
+ return ifcFfcStrength(KeyUtil.getKeySize(k))
+ + "withRSA";
+ default:
+ return null;
+ }
+ }
+
+ // Values from SP800-57 part 1 rev 3 tables 2 and three
+ private static String ecStrength (int bitLength) {
+ if (bitLength >= 512) { // 256 bits of strength
+ return "SHA512";
+ } else if (bitLength >= 384) { // 192 bits of strength
+ return "SHA384";
+ } else { // 128 bits of strength and less
+ return "SHA256";
+ }
+ }
+
+ // same values for RSA and DSA
+ private static String ifcFfcStrength (int bitLength) {
+ if (bitLength > 7680) { // 256 bits
+ return "SHA512";
+ } else if (bitLength > 3072) { // 192 bits
+ return "SHA384";
+ } else { // 128 bits and less
+ return "SHA256";
+ }
+ }
}
--- a/jdk/src/java.base/share/classes/sun/security/x509/AuthorityKeyIdentifierExtension.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/security/x509/AuthorityKeyIdentifierExtension.java Wed Jul 05 21:02:29 2017 +0200
@@ -310,4 +310,16 @@
public String getName() {
return (NAME);
}
+
+ /**
+ * Return the encoded key identifier, or null if not specified.
+ */
+ public byte[] getEncodedKeyIdentifier() throws IOException {
+ if (id != null) {
+ DerOutputStream derOut = new DerOutputStream();
+ id.encode(derOut);
+ return derOut.toByteArray();
+ }
+ return null;
+ }
}
--- a/jdk/src/java.base/share/classes/sun/util/logging/LoggingProxy.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.util.logging;
-
-/**
- * A proxy interface for the java.util.logging support.
- *
- * @see sun.util.logging.LoggingSupport
- */
-public interface LoggingProxy {
- // Methods to bridge java.util.logging.Logger methods
- public Object getLogger(String name);
-
- public Object getLevel(Object logger);
-
- public void setLevel(Object logger, Object newLevel);
-
- public boolean isLoggable(Object logger, Object level);
-
- public void log(Object logger, Object level, String msg);
-
- public void log(Object logger, Object level, String msg, Throwable t);
-
- public void log(Object logger, Object level, String msg, Object... params);
-
- // Methods to bridge java.util.logging.LoggingMXBean methods
- public java.util.List<String> getLoggerNames();
-
- public String getLoggerLevel(String loggerName);
-
- public void setLoggerLevel(String loggerName, String levelName);
-
- public String getParentLoggerName(String loggerName);
-
- // Methods to bridge Level.parse() and Level.getName() method
- public Object parseLevel(String levelName);
-
- public String getLevelName(Object level);
-
- public int getLevelValue(Object level);
-
- // return the logging property
- public String getProperty(String key);
-}
--- a/jdk/src/java.base/share/classes/sun/util/logging/LoggingSupport.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,190 +0,0 @@
-/*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.util.logging;
-
-import java.lang.reflect.Field;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.time.ZonedDateTime;
-
-/**
- * Internal API to support JRE implementation to detect if the java.util.logging
- * support is available but with no dependency on the java.util.logging
- * classes. This LoggingSupport class provides several static methods to
- * access the java.util.logging functionality that requires the caller
- * to ensure that the logging support is {@linkplain #isAvailable available}
- * before invoking it.
- *
- * @see sun.util.logging.PlatformLogger if you want to log messages even
- * if the logging support is not available
- */
-public class LoggingSupport {
- private LoggingSupport() { }
-
- private static final LoggingProxy proxy =
- AccessController.doPrivileged(new PrivilegedAction<LoggingProxy>() {
- public LoggingProxy run() {
- try {
- // create a LoggingProxyImpl instance when
- // java.util.logging classes exist
- Class<?> c = Class.forName("java.util.logging.LoggingProxyImpl", true, null);
- Field f = c.getDeclaredField("INSTANCE");
- f.setAccessible(true);
- return (LoggingProxy) f.get(null);
- } catch (ClassNotFoundException cnf) {
- return null;
- } catch (NoSuchFieldException e) {
- throw new AssertionError(e);
- } catch (IllegalAccessException e) {
- throw new AssertionError(e);
- }
- }});
-
- /**
- * Returns true if java.util.logging support is available.
- */
- public static boolean isAvailable() {
- return proxy != null;
- }
-
- private static void ensureAvailable() {
- if (proxy == null)
- throw new AssertionError("Should not here");
- }
-
- public static java.util.List<String> getLoggerNames() {
- ensureAvailable();
- return proxy.getLoggerNames();
- }
- public static String getLoggerLevel(String loggerName) {
- ensureAvailable();
- return proxy.getLoggerLevel(loggerName);
- }
-
- public static void setLoggerLevel(String loggerName, String levelName) {
- ensureAvailable();
- proxy.setLoggerLevel(loggerName, levelName);
- }
-
- public static String getParentLoggerName(String loggerName) {
- ensureAvailable();
- return proxy.getParentLoggerName(loggerName);
- }
-
- public static Object getLogger(String name) {
- ensureAvailable();
- return proxy.getLogger(name);
- }
-
- public static Object getLevel(Object logger) {
- ensureAvailable();
- return proxy.getLevel(logger);
- }
-
- public static void setLevel(Object logger, Object newLevel) {
- ensureAvailable();
- proxy.setLevel(logger, newLevel);
- }
-
- public static boolean isLoggable(Object logger, Object level) {
- ensureAvailable();
- return proxy.isLoggable(logger,level);
- }
-
- public static void log(Object logger, Object level, String msg) {
- ensureAvailable();
- proxy.log(logger, level, msg);
- }
-
- public static void log(Object logger, Object level, String msg, Throwable t) {
- ensureAvailable();
- proxy.log(logger, level, msg, t);
- }
-
- public static void log(Object logger, Object level, String msg, Object... params) {
- ensureAvailable();
- proxy.log(logger, level, msg, params);
- }
-
- public static Object parseLevel(String levelName) {
- ensureAvailable();
- return proxy.parseLevel(levelName);
- }
-
- public static String getLevelName(Object level) {
- ensureAvailable();
- return proxy.getLevelName(level);
- }
-
- public static int getLevelValue(Object level) {
- ensureAvailable();
- return proxy.getLevelValue(level);
- }
-
- // Since JDK 9, logging uses java.time to get more precise time stamps.
- // It is possible to configure the simple format to print nano seconds (.%1$tN)
- // by specifying:
- // java.util.logging.SimpleFormatter.format=%1$tb %1$td, %1$tY %1$tl:%1$tM:%1$tS.%1$tN %1$Tp %2$s%n%4$s: %5$s%6$s%n
- // in the logging configuration
- private static final String DEFAULT_FORMAT =
- "%1$tb %1$td, %1$tY %1$tl:%1$tM:%1$tS %1$Tp %2$s%n%4$s: %5$s%6$s%n";
-
- private static final String FORMAT_PROP_KEY = "java.util.logging.SimpleFormatter.format";
- public static String getSimpleFormat() {
- return getSimpleFormat(true);
- }
-
- // useProxy if true will cause initialization of
- // java.util.logging and read its configuration
- static String getSimpleFormat(boolean useProxy) {
- String format =
- AccessController.doPrivileged(
- new PrivilegedAction<String>() {
- public String run() {
- return System.getProperty(FORMAT_PROP_KEY);
- }
- });
-
- if (useProxy && proxy != null && format == null) {
- format = proxy.getProperty(FORMAT_PROP_KEY);
- }
-
- if (format != null) {
- try {
- // validate the user-defined format string
- String.format(format, ZonedDateTime.now(), "", "", "", "", "");
- } catch (IllegalArgumentException e) {
- // illegal syntax; fall back to the default format
- format = DEFAULT_FORMAT;
- }
- } else {
- format = DEFAULT_FORMAT;
- }
- return format;
- }
-
-}
--- a/jdk/src/java.base/share/classes/sun/util/logging/PlatformLogger.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/util/logging/PlatformLogger.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,20 +27,13 @@
package sun.util.logging;
import java.lang.ref.WeakReference;
-import java.io.PrintStream;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.time.Clock;
-import java.time.Instant;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
-import jdk.internal.misc.JavaLangAccess;
-import jdk.internal.misc.SharedSecrets;
+import java.util.ResourceBundle;
+import java.util.function.Supplier;
+import jdk.internal.logger.LazyLoggers;
+import jdk.internal.logger.LoggerWrapper;
/**
* Platform logger provides an API for the JRE components to log
@@ -56,18 +49,28 @@
* the stack frame information issuing the log message.
*
* When the logging facility is enabled (at startup or runtime),
- * the java.util.logging.Logger will be created for each platform
+ * the backend logger will be created for each platform
* logger and all log messages will be forwarded to the Logger
* to handle.
*
+ * The PlatformLogger uses an underlying PlatformLogger.Bridge instance
+ * obtained by calling {@link PlatformLogger.Bridge#convert PlatformLogger.Bridge.convert(}
+ * {@link jdk.internal.logger.LazyLoggers#getLazyLogger(java.lang.String, java.lang.Class)
+ * jdk.internal.logger.LazyLoggers#getLazyLogger(name, PlatformLogger.class))}.
+ *
* Logging facility is "enabled" when one of the following
* conditions is met:
- * 1) a system property "java.util.logging.config.class" or
- * "java.util.logging.config.file" is set
- * 2) java.util.logging.LogManager or java.util.logging.Logger
- * is referenced that will trigger the logging initialization.
+ * 1) ServiceLoader.load({@link java.lang.System.LoggerFinder LoggerFinder.class},
+ * ClassLoader.getSystemClassLoader()).iterator().hasNext().
+ * 2) ServiceLoader.loadInstalled({@link jdk.internal.logger.DefaultLoggerFinder}).iterator().hasNext(),
+ * and 2.1) a system property "java.util.logging.config.class" or
+ * "java.util.logging.config.file" is set
+ * or 2.2) java.util.logging.LogManager or java.util.logging.Logger
+ * is referenced that will trigger the logging initialization.
*
* Default logging configuration:
+ *
+ * No LoggerFinder service implementation declared
* global logging level = INFO
* handlers = java.util.logging.ConsoleHandler
* java.util.logging.ConsoleHandler.level = INFO
@@ -84,71 +87,84 @@
* The platform loggers are designed for JDK developers use and
* this limitation can be workaround with setting
* -Djava.util.logging.config.file system property.
+ * <br>
+ * Calling PlatformLogger.setLevel will not work when there is a custom
+ * LoggerFinder installed - and as a consequence {@link #setLevel setLevel}
+ * is now deprecated.
*
* @since 1.7
*/
public class PlatformLogger {
- // The integer values must match that of {@code java.util.logging.Level}
- // objects.
- private static final int OFF = Integer.MAX_VALUE;
- private static final int SEVERE = 1000;
- private static final int WARNING = 900;
- private static final int INFO = 800;
- private static final int CONFIG = 700;
- private static final int FINE = 500;
- private static final int FINER = 400;
- private static final int FINEST = 300;
- private static final int ALL = Integer.MIN_VALUE;
-
/**
* PlatformLogger logging levels.
*/
public static enum Level {
// The name and value must match that of {@code java.util.logging.Level}s.
// Declare in ascending order of the given value for binary search.
- ALL,
- FINEST,
- FINER,
- FINE,
- CONFIG,
- INFO,
- WARNING,
- SEVERE,
- OFF;
+ ALL(System.Logger.Level.ALL),
+ FINEST(System.Logger.Level.TRACE),
+ FINER(System.Logger.Level.TRACE),
+ FINE(System.Logger.Level.DEBUG),
+ CONFIG(System.Logger.Level.DEBUG),
+ INFO(System.Logger.Level.INFO),
+ WARNING(System.Logger.Level.WARNING),
+ SEVERE(System.Logger.Level.ERROR),
+ OFF(System.Logger.Level.OFF);
- /**
- * Associated java.util.logging.Level lazily initialized in
- * JavaLoggerProxy's static initializer only once
- * when java.util.logging is available and enabled.
- * Only accessed by JavaLoggerProxy.
- */
- /* java.util.logging.Level */ Object javaLevel;
+ final System.Logger.Level systemLevel;
+ Level(System.Logger.Level systemLevel) {
+ this.systemLevel = systemLevel;
+ }
+
+ // The integer values must match that of {@code java.util.logging.Level}
+ // objects.
+ private static final int SEVERITY_OFF = Integer.MAX_VALUE;
+ private static final int SEVERITY_SEVERE = 1000;
+ private static final int SEVERITY_WARNING = 900;
+ private static final int SEVERITY_INFO = 800;
+ private static final int SEVERITY_CONFIG = 700;
+ private static final int SEVERITY_FINE = 500;
+ private static final int SEVERITY_FINER = 400;
+ private static final int SEVERITY_FINEST = 300;
+ private static final int SEVERITY_ALL = Integer.MIN_VALUE;
// ascending order for binary search matching the list of enum constants
private static final int[] LEVEL_VALUES = new int[] {
- PlatformLogger.ALL, PlatformLogger.FINEST, PlatformLogger.FINER,
- PlatformLogger.FINE, PlatformLogger.CONFIG, PlatformLogger.INFO,
- PlatformLogger.WARNING, PlatformLogger.SEVERE, PlatformLogger.OFF
+ SEVERITY_ALL, SEVERITY_FINEST, SEVERITY_FINER,
+ SEVERITY_FINE, SEVERITY_CONFIG, SEVERITY_INFO,
+ SEVERITY_WARNING, SEVERITY_SEVERE, SEVERITY_OFF
};
+ public System.Logger.Level systemLevel() {
+ return systemLevel;
+ }
+
public int intValue() {
return LEVEL_VALUES[this.ordinal()];
}
- static Level valueOf(int level) {
+ /**
+ * Maps a severity value to an effective logger level.
+ * @param level The severity of the messages that should be
+ * logged with a logger set to the returned level.
+ * @return The effective logger level, which is the nearest Level value
+ * whose severity is greater or equal to the given level.
+ * For level > SEVERE (OFF excluded), return SEVERE.
+ */
+ public static Level valueOf(int level) {
switch (level) {
// ordering per the highest occurrences in the jdk source
// finest, fine, finer, info first
- case PlatformLogger.FINEST : return Level.FINEST;
- case PlatformLogger.FINE : return Level.FINE;
- case PlatformLogger.FINER : return Level.FINER;
- case PlatformLogger.INFO : return Level.INFO;
- case PlatformLogger.WARNING : return Level.WARNING;
- case PlatformLogger.CONFIG : return Level.CONFIG;
- case PlatformLogger.SEVERE : return Level.SEVERE;
- case PlatformLogger.OFF : return Level.OFF;
- case PlatformLogger.ALL : return Level.ALL;
+ case SEVERITY_FINEST : return Level.FINEST;
+ case SEVERITY_FINE : return Level.FINE;
+ case SEVERITY_FINER : return Level.FINER;
+ case SEVERITY_INFO : return Level.INFO;
+ case SEVERITY_WARNING : return Level.WARNING;
+ case SEVERITY_CONFIG : return Level.CONFIG;
+ case SEVERITY_SEVERE : return Level.SEVERE;
+ case SEVERITY_OFF : return Level.OFF;
+ case SEVERITY_ALL : return Level.ALL;
}
// return the nearest Level value >= the given level,
// for level > SEVERE, return SEVERE and exclude OFF
@@ -157,39 +173,110 @@
}
}
- private static final Level DEFAULT_LEVEL = Level.INFO;
- private static boolean loggingEnabled;
- static {
- loggingEnabled = AccessController.doPrivileged(
- new PrivilegedAction<>() {
- public Boolean run() {
- String cname = System.getProperty("java.util.logging.config.class");
- String fname = System.getProperty("java.util.logging.config.file");
- return (cname != null || fname != null);
- }
- });
+ /**
+ *
+ * The PlatformLogger.Bridge interface is implemented by the System.Logger
+ * objects returned by our default JUL provider - so that JRE classes using
+ * PlatformLogger see no difference when JUL is the actual backend.
+ *
+ * PlatformLogger is now only a thin adaptation layer over the same
+ * loggers than returned by java.lang.System.getLogger(String name).
+ *
+ * The recommendation for JRE classes going forward is to use
+ * java.lang.System.getLogger(String name), which will
+ * use Lazy Loggers when possible and necessary.
+ *
+ */
+ public static interface Bridge {
+
+ /**
+ * Gets the name for this platform logger.
+ * @return the name of the platform logger.
+ */
+ public String getName();
+
+ /**
+ * Returns true if a message of the given level would actually
+ * be logged by this logger.
+ * @param level the level
+ * @return whether a message of that level would be logged
+ */
+ public boolean isLoggable(Level level);
+ public boolean isEnabled();
- // force loading of all JavaLoggerProxy (sub)classes to make JIT de-optimizations
- // less probable. Don't initialize JavaLoggerProxy class since
- // java.util.logging may not be enabled.
- try {
- Class.forName("sun.util.logging.PlatformLogger$DefaultLoggerProxy",
- false,
- PlatformLogger.class.getClassLoader());
- Class.forName("sun.util.logging.PlatformLogger$JavaLoggerProxy",
- false, // do not invoke class initializer
- PlatformLogger.class.getClassLoader());
- } catch (ClassNotFoundException ex) {
- throw new InternalError(ex);
+ public void log(Level level, String msg);
+ public void log(Level level, String msg, Throwable thrown);
+ public void log(Level level, String msg, Object... params);
+ public void log(Level level, Supplier<String> msgSupplier);
+ public void log(Level level, Throwable thrown, Supplier<String> msgSupplier);
+ public void logp(Level level, String sourceClass, String sourceMethod, String msg);
+ public void logp(Level level, String sourceClass, String sourceMethod,
+ Supplier<String> msgSupplier);
+ public void logp(Level level, String sourceClass, String sourceMethod,
+ String msg, Object... params);
+ public void logp(Level level, String sourceClass, String sourceMethod,
+ String msg, Throwable thrown);
+ public void logp(Level level, String sourceClass, String sourceMethod,
+ Throwable thrown, Supplier<String> msgSupplier);
+ public void logrb(Level level, String sourceClass, String sourceMethod,
+ ResourceBundle bundle, String msg, Object... params);
+ public void logrb(Level level, String sourceClass, String sourceMethod,
+ ResourceBundle bundle, String msg, Throwable thrown);
+ public void logrb(Level level, ResourceBundle bundle, String msg,
+ Object... params);
+ public void logrb(Level level, ResourceBundle bundle, String msg,
+ Throwable thrown);
+
+
+ public static Bridge convert(System.Logger logger) {
+ if (logger instanceof PlatformLogger.Bridge) {
+ return (Bridge) logger;
+ } else {
+ return new LoggerWrapper<>(logger);
+ }
+ }
+ }
+
+ /**
+ * The {@code PlatformLogger.ConfigurableBridge} interface is used to
+ * implement the deprecated {@link PlatformLogger#setLevel} method.
+ *
+ * PlatformLogger is now only a thin adaptation layer over the same
+ * loggers than returned by java.lang.System.getLogger(String name).
+ *
+ * The recommendation for JRE classes going forward is to use
+ * java.lang.System.getLogger(String name), which will
+ * use Lazy Loggers when possible and necessary.
+ *
+ */
+ public static interface ConfigurableBridge {
+
+ public abstract class LoggerConfiguration {
+ public abstract Level getPlatformLevel();
+ public abstract void setPlatformLevel(Level level);
+ }
+
+ public default LoggerConfiguration getLoggerConfiguration() {
+ return null;
+ }
+
+ public static LoggerConfiguration getLoggerConfiguration(PlatformLogger.Bridge logger) {
+ if (logger instanceof PlatformLogger.ConfigurableBridge) {
+ return ((ConfigurableBridge) logger).getLoggerConfiguration();
+ } else {
+ return null;
+ }
}
}
// Table of known loggers. Maps names to PlatformLoggers.
- private static Map<String,WeakReference<PlatformLogger>> loggers =
+ private static final Map<String,WeakReference<PlatformLogger>> loggers =
new HashMap<>();
/**
* Returns a PlatformLogger of a given name.
+ * @param name the name of the logger
+ * @return a PlatformLogger
*/
public static synchronized PlatformLogger getLogger(String name) {
PlatformLogger log = null;
@@ -198,56 +285,31 @@
log = ref.get();
}
if (log == null) {
- log = new PlatformLogger(name);
+ log = new PlatformLogger(PlatformLogger.Bridge.convert(
+ // We pass PlatformLogger.class rather than the actual caller
+ // because we want PlatformLoggers to be system loggers: we
+ // won't need to resolve any resource bundles anyway.
+ // Note: Many unit tests depend on the fact that
+ // PlatformLogger.getLoggerFromFinder is not caller sensitive.
+ LazyLoggers.getLazyLogger(name, PlatformLogger.class)));
loggers.put(name, new WeakReference<>(log));
}
return log;
}
- /**
- * Initialize java.util.logging.Logger objects for all platform loggers.
- * This method is called from LogManager.readPrimordialConfiguration().
- */
- public static synchronized void redirectPlatformLoggers() {
- if (loggingEnabled || !LoggingSupport.isAvailable()) return;
-
- loggingEnabled = true;
- for (Map.Entry<String, WeakReference<PlatformLogger>> entry : loggers.entrySet()) {
- WeakReference<PlatformLogger> ref = entry.getValue();
- PlatformLogger plog = ref.get();
- if (plog != null) {
- plog.redirectToJavaLoggerProxy();
- }
- }
- }
-
- /**
- * Creates a new JavaLoggerProxy and redirects the platform logger to it
- */
- private void redirectToJavaLoggerProxy() {
- DefaultLoggerProxy lp = DefaultLoggerProxy.class.cast(this.loggerProxy);
- JavaLoggerProxy jlp = new JavaLoggerProxy(lp.name, lp.level);
- // the order of assignments is important
- this.javaLoggerProxy = jlp; // isLoggable checks javaLoggerProxy if set
- this.loggerProxy = jlp;
- }
-
- // DefaultLoggerProxy may be replaced with a JavaLoggerProxy object
- // when the java.util.logging facility is enabled
- private volatile LoggerProxy loggerProxy;
- // javaLoggerProxy is only set when the java.util.logging facility is enabled
- private volatile JavaLoggerProxy javaLoggerProxy;
- private PlatformLogger(String name) {
- if (loggingEnabled) {
- this.loggerProxy = this.javaLoggerProxy = new JavaLoggerProxy(name);
- } else {
- this.loggerProxy = new DefaultLoggerProxy(name);
- }
+ // The system loggerProxy returned by LazyLoggers
+ // This may be a lazy logger - see jdk.internal.logger.LazyLoggers,
+ // or may be a Logger instance (or a wrapper thereof).
+ //
+ private final PlatformLogger.Bridge loggerProxy;
+ private PlatformLogger(PlatformLogger.Bridge loggerProxy) {
+ this.loggerProxy = loggerProxy;
}
/**
* A convenience method to test if the logger is turned off.
* (i.e. its level is OFF).
+ * @return whether the logger is turned off.
*/
public boolean isEnabled() {
return loggerProxy.isEnabled();
@@ -255,22 +317,24 @@
/**
* Gets the name for this platform logger.
+ * @return the name of the platform logger.
*/
public String getName() {
- return loggerProxy.name;
+ return loggerProxy.getName();
}
/**
* Returns true if a message of the given level would actually
* be logged by this logger.
+ * @param level the level
+ * @return whether a message of that level would be logged
*/
public boolean isLoggable(Level level) {
if (level == null) {
throw new NullPointerException();
}
- // performance-sensitive method: use two monomorphic call-sites
- JavaLoggerProxy jlp = javaLoggerProxy;
- return jlp != null ? jlp.isLoggable(level) : loggerProxy.isLoggable(level);
+
+ return loggerProxy.isLoggable(level);
}
/**
@@ -281,13 +345,15 @@
* @return this PlatformLogger's level
*/
public Level level() {
- return loggerProxy.getLevel();
+ final ConfigurableBridge.LoggerConfiguration spi =
+ PlatformLogger.ConfigurableBridge.getLoggerConfiguration(loggerProxy);
+ return spi == null ? null : spi.getPlatformLevel();
}
/**
* Set the log level specifying which message levels will be
* logged by this logger. Message levels lower than this
- * value will be discarded. The level value {@link #OFF}
+ * value will be discarded. The level value {@link Level#OFF}
* can be used to turn off logging.
* <p>
* If the new level is null, it means that this node should
@@ -295,366 +361,153 @@
* (non-null) level value.
*
* @param newLevel the new value for the log level (may be null)
+ * @deprecated Platform Loggers should not be configured programmatically.
+ * This method will not work if a custom {@link
+ * java.lang.System.LoggerFinder} is installed.
*/
+ @Deprecated
public void setLevel(Level newLevel) {
- loggerProxy.setLevel(newLevel);
+ final ConfigurableBridge.LoggerConfiguration spi =
+ PlatformLogger.ConfigurableBridge.getLoggerConfiguration(loggerProxy);;
+ if (spi != null) {
+ spi.setPlatformLevel(newLevel);
+ }
}
/**
* Logs a SEVERE message.
+ * @param msg the message
*/
public void severe(String msg) {
- loggerProxy.doLog(Level.SEVERE, msg);
+ loggerProxy.log(Level.SEVERE, msg, (Object[])null);
}
public void severe(String msg, Throwable t) {
- loggerProxy.doLog(Level.SEVERE, msg, t);
+ loggerProxy.log(Level.SEVERE, msg, t);
}
public void severe(String msg, Object... params) {
- loggerProxy.doLog(Level.SEVERE, msg, params);
+ loggerProxy.log(Level.SEVERE, msg, params);
}
/**
* Logs a WARNING message.
+ * @param msg the message
*/
public void warning(String msg) {
- loggerProxy.doLog(Level.WARNING, msg);
+ loggerProxy.log(Level.WARNING, msg, (Object[])null);
}
public void warning(String msg, Throwable t) {
- loggerProxy.doLog(Level.WARNING, msg, t);
+ loggerProxy.log(Level.WARNING, msg, t);
}
public void warning(String msg, Object... params) {
- loggerProxy.doLog(Level.WARNING, msg, params);
+ loggerProxy.log(Level.WARNING, msg, params);
}
/**
* Logs an INFO message.
+ * @param msg the message
*/
public void info(String msg) {
- loggerProxy.doLog(Level.INFO, msg);
+ loggerProxy.log(Level.INFO, msg, (Object[])null);
}
public void info(String msg, Throwable t) {
- loggerProxy.doLog(Level.INFO, msg, t);
+ loggerProxy.log(Level.INFO, msg, t);
}
public void info(String msg, Object... params) {
- loggerProxy.doLog(Level.INFO, msg, params);
+ loggerProxy.log(Level.INFO, msg, params);
}
/**
* Logs a CONFIG message.
+ * @param msg the message
*/
public void config(String msg) {
- loggerProxy.doLog(Level.CONFIG, msg);
+ loggerProxy.log(Level.CONFIG, msg, (Object[])null);
}
public void config(String msg, Throwable t) {
- loggerProxy.doLog(Level.CONFIG, msg, t);
+ loggerProxy.log(Level.CONFIG, msg, t);
}
public void config(String msg, Object... params) {
- loggerProxy.doLog(Level.CONFIG, msg, params);
+ loggerProxy.log(Level.CONFIG, msg, params);
}
/**
* Logs a FINE message.
+ * @param msg the message
*/
public void fine(String msg) {
- loggerProxy.doLog(Level.FINE, msg);
+ loggerProxy.log(Level.FINE, msg, (Object[])null);
}
public void fine(String msg, Throwable t) {
- loggerProxy.doLog(Level.FINE, msg, t);
+ loggerProxy.log(Level.FINE, msg, t);
}
public void fine(String msg, Object... params) {
- loggerProxy.doLog(Level.FINE, msg, params);
+ loggerProxy.log(Level.FINE, msg, params);
}
/**
* Logs a FINER message.
+ * @param msg the message
*/
public void finer(String msg) {
- loggerProxy.doLog(Level.FINER, msg);
+ loggerProxy.log(Level.FINER, msg, (Object[])null);
}
public void finer(String msg, Throwable t) {
- loggerProxy.doLog(Level.FINER, msg, t);
+ loggerProxy.log(Level.FINER, msg, t);
}
public void finer(String msg, Object... params) {
- loggerProxy.doLog(Level.FINER, msg, params);
+ loggerProxy.log(Level.FINER, msg, params);
}
/**
* Logs a FINEST message.
+ * @param msg the message
*/
public void finest(String msg) {
- loggerProxy.doLog(Level.FINEST, msg);
+ loggerProxy.log(Level.FINEST, msg, (Object[])null);
}
public void finest(String msg, Throwable t) {
- loggerProxy.doLog(Level.FINEST, msg, t);
+ loggerProxy.log(Level.FINEST, msg, t);
}
public void finest(String msg, Object... params) {
- loggerProxy.doLog(Level.FINEST, msg, params);
- }
-
- /**
- * Abstract base class for logging support, defining the API and common field.
- */
- private abstract static class LoggerProxy {
- final String name;
-
- protected LoggerProxy(String name) {
- this.name = name;
- }
-
- abstract boolean isEnabled();
-
- abstract Level getLevel();
- abstract void setLevel(Level newLevel);
-
- abstract void doLog(Level level, String msg);
- abstract void doLog(Level level, String msg, Throwable thrown);
- abstract void doLog(Level level, String msg, Object... params);
-
- abstract boolean isLoggable(Level level);
+ loggerProxy.log(Level.FINEST, msg, params);
}
-
- private static final class DefaultLoggerProxy extends LoggerProxy {
- /**
- * Default platform logging support - output messages to System.err -
- * equivalent to ConsoleHandler with SimpleFormatter.
- */
- private static PrintStream outputStream() {
- return System.err;
- }
-
- volatile Level effectiveLevel; // effective level (never null)
- volatile Level level; // current level set for this node (may be null)
-
- DefaultLoggerProxy(String name) {
- super(name);
- this.effectiveLevel = deriveEffectiveLevel(null);
- this.level = null;
- }
-
- boolean isEnabled() {
- return effectiveLevel != Level.OFF;
- }
-
- Level getLevel() {
- return level;
- }
-
- void setLevel(Level newLevel) {
- Level oldLevel = level;
- if (oldLevel != newLevel) {
- level = newLevel;
- effectiveLevel = deriveEffectiveLevel(newLevel);
- }
- }
-
- void doLog(Level level, String msg) {
- if (isLoggable(level)) {
- outputStream().print(format(level, msg, null));
- }
- }
-
- void doLog(Level level, String msg, Throwable thrown) {
- if (isLoggable(level)) {
- outputStream().print(format(level, msg, thrown));
- }
- }
-
- void doLog(Level level, String msg, Object... params) {
- if (isLoggable(level)) {
- String newMsg = formatMessage(msg, params);
- outputStream().print(format(level, newMsg, null));
- }
- }
-
- boolean isLoggable(Level level) {
- Level effectiveLevel = this.effectiveLevel;
- return level.intValue() >= effectiveLevel.intValue() && effectiveLevel != Level.OFF;
- }
-
- // derive effective level (could do inheritance search like j.u.l.Logger)
- private Level deriveEffectiveLevel(Level level) {
- return level == null ? DEFAULT_LEVEL : level;
- }
+ // ------------------------------------
+ // Maps used for Level conversion
+ // ------------------------------------
- // Copied from java.util.logging.Formatter.formatMessage
- private String formatMessage(String format, Object... parameters) {
- // Do the formatting.
- try {
- if (parameters == null || parameters.length == 0) {
- // No parameters. Just return format string.
- return format;
- }
- // Is it a java.text style format?
- // Ideally we could match with
- // Pattern.compile("\\{\\d").matcher(format).find())
- // However the cost is 14% higher, so we cheaply check for
- // 1 of the first 4 parameters
- if (format.indexOf("{0") >= 0 || format.indexOf("{1") >=0 ||
- format.indexOf("{2") >=0|| format.indexOf("{3") >=0) {
- return java.text.MessageFormat.format(format, parameters);
- }
- return format;
- } catch (Exception ex) {
- // Formatting failed: use format string.
- return format;
- }
- }
-
- private static final String formatString =
- LoggingSupport.getSimpleFormat(false); // don't check logging.properties
- private final ZoneId zoneId = ZoneId.systemDefault();
- private synchronized String format(Level level, String msg, Throwable thrown) {
- ZonedDateTime zdt = ZonedDateTime.now(zoneId);
- String throwable = "";
- if (thrown != null) {
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- pw.println();
- thrown.printStackTrace(pw);
- pw.close();
- throwable = sw.toString();
- }
+ // This map is indexed by java.util.spi.Logger.Level.ordinal() and returns
+ // a PlatformLogger.Level
+ //
+ // ALL, TRACE, DEBUG, INFO, WARNING, ERROR, OFF
+ private static final Level[] spi2platformLevelMapping = {
+ Level.ALL, // mapped from ALL
+ Level.FINER, // mapped from TRACE
+ Level.FINE, // mapped from DEBUG
+ Level.INFO, // mapped from INFO
+ Level.WARNING, // mapped from WARNING
+ Level.SEVERE, // mapped from ERROR
+ Level.OFF // mapped from OFF
+ };
- return String.format(formatString,
- zdt,
- getCallerInfo(),
- name,
- level.name(),
- msg,
- throwable);
- }
-
- // Returns the caller's class and method's name; best effort
- // if cannot infer, return the logger's name.
- private String getCallerInfo() {
- String sourceClassName = null;
- String sourceMethodName = null;
-
- JavaLangAccess access = SharedSecrets.getJavaLangAccess();
- Throwable throwable = new Throwable();
- int depth = access.getStackTraceDepth(throwable);
-
- String logClassName = "sun.util.logging.PlatformLogger";
- boolean lookingForLogger = true;
- for (int ix = 0; ix < depth; ix++) {
- // Calling getStackTraceElement directly prevents the VM
- // from paying the cost of building the entire stack frame.
- StackTraceElement frame =
- access.getStackTraceElement(throwable, ix);
- String cname = frame.getClassName();
- if (lookingForLogger) {
- // Skip all frames until we have found the first logger frame.
- if (cname.equals(logClassName)) {
- lookingForLogger = false;
- }
- } else {
- if (!cname.equals(logClassName)) {
- // We've found the relevant frame.
- sourceClassName = cname;
- sourceMethodName = frame.getMethodName();
- break;
- }
- }
- }
-
- if (sourceClassName != null) {
- return sourceClassName + " " + sourceMethodName;
- } else {
- return name;
- }
- }
+ public static Level toPlatformLevel(java.lang.System.Logger.Level level) {
+ if (level == null) return null;
+ assert level.ordinal() < spi2platformLevelMapping.length;
+ return spi2platformLevelMapping[level.ordinal()];
}
- /**
- * JavaLoggerProxy forwards all the calls to its corresponding
- * java.util.logging.Logger object.
- */
- private static final class JavaLoggerProxy extends LoggerProxy {
- // initialize javaLevel fields for mapping from Level enum -> j.u.l.Level object
- static {
- for (Level level : Level.values()) {
- level.javaLevel = LoggingSupport.parseLevel(level.name());
- }
- }
-
- private final /* java.util.logging.Logger */ Object javaLogger;
-
- JavaLoggerProxy(String name) {
- this(name, null);
- }
-
- JavaLoggerProxy(String name, Level level) {
- super(name);
- this.javaLogger = LoggingSupport.getLogger(name);
- if (level != null) {
- // level has been updated and so set the Logger's level
- LoggingSupport.setLevel(javaLogger, level.javaLevel);
- }
- }
-
- void doLog(Level level, String msg) {
- LoggingSupport.log(javaLogger, level.javaLevel, msg);
- }
-
- void doLog(Level level, String msg, Throwable t) {
- LoggingSupport.log(javaLogger, level.javaLevel, msg, t);
- }
-
- void doLog(Level level, String msg, Object... params) {
- if (!isLoggable(level)) {
- return;
- }
- // only pass String objects to the j.u.l.Logger which may
- // be created by untrusted code
- int len = (params != null) ? params.length : 0;
- Object[] sparams = new String[len];
- for (int i = 0; i < len; i++) {
- sparams [i] = String.valueOf(params[i]);
- }
- LoggingSupport.log(javaLogger, level.javaLevel, msg, sparams);
- }
-
- boolean isEnabled() {
- return LoggingSupport.isLoggable(javaLogger, Level.OFF.javaLevel);
- }
-
- /**
- * Returns the PlatformLogger.Level mapped from j.u.l.Level
- * set in the logger. If the j.u.l.Logger is set to a custom Level,
- * this method will return the nearest Level.
- */
- Level getLevel() {
- Object javaLevel = LoggingSupport.getLevel(javaLogger);
- if (javaLevel == null) return null;
-
- try {
- return Level.valueOf(LoggingSupport.getLevelName(javaLevel));
- } catch (IllegalArgumentException e) {
- return Level.valueOf(LoggingSupport.getLevelValue(javaLevel));
- }
- }
-
- void setLevel(Level level) {
- LoggingSupport.setLevel(javaLogger, level == null ? null : level.javaLevel);
- }
-
- boolean isLoggable(Level level) {
- return LoggingSupport.isLoggable(javaLogger, level.javaLevel);
- }
- }
}
--- a/jdk/src/java.base/share/native/libjimage/ImageNativeSubstrate.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/native/libjimage/ImageNativeSubstrate.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -202,6 +202,9 @@
if (reader == NULL) return NULL;
// Convert byte array to a cstring.
char* path = new char[size + 1];
+ if (path == NULL) {
+ return NULL;
+ }
memcpy(path, rawBytes, size);
path[size] = '\0';
// Locate resource location data.
--- a/jdk/src/java.base/share/native/libjimage/imageFile.cpp Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/share/native/libjimage/imageFile.cpp Wed Jul 05 21:02:29 2017 +0200
@@ -149,6 +149,7 @@
if (found) {
u8 data_size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
_data = new u1[(size_t)data_size];
+ assert(_data != NULL && "allocation failed");
_image_file->get_resource(location, _data);
// Map out the header.
_header = (Header*)_data;
@@ -254,6 +255,7 @@
// Construct an array of all the package entries.
u4 count = data->package_count(_endian);
const char** packages = new const char*[count + 1];
+ assert(packages != NULL && "allocation failed");
s4 package_offset = data->package_offset(_endian);
for (u4 i = 0; i < count; i++) {
u4 package_name_offset = mtp_package(package_offset + i);
@@ -271,6 +273,7 @@
// to share an open image.
ImageFileReaderTable::ImageFileReaderTable() : _count(0), _max(_growth) {
_table = new ImageFileReader*[_max];
+ assert( _table != NULL && "allocation failed");
}
ImageFileReaderTable::~ImageFileReaderTable() {
@@ -330,6 +333,7 @@
// Retrieve table entry.
ImageFileReader* reader = _reader_table.get(i);
// If name matches, then reuse (bump up use count.)
+ assert(reader->name() != NULL && "reader->name must not be null");
if (strcmp(reader->name(), name) == 0) {
reader->inc_use();
return reader;
@@ -339,20 +343,20 @@
// Need a new image reader.
ImageFileReader* reader = new ImageFileReader(name, big_endian);
- bool opened = reader->open();
- // If failed to open.
- if (!opened) {
+ if (reader == NULL || !reader->open()) {
+ // Failed to open.
delete reader;
return NULL;
}
// Lock to update
SimpleCriticalSectionLock cs(&_reader_table_lock);
- // Search for an exist image file.
+ // Search for an existing image file.
for (u4 i = 0; i < _reader_table.count(); i++) {
// Retrieve table entry.
ImageFileReader* existing_reader = _reader_table.get(i);
// If name matches, then reuse (bump up use count.)
+ assert(reader->name() != NULL && "reader->name still must not be null");
if (strcmp(existing_reader->name(), name) == 0) {
existing_reader->inc_use();
reader->close();
@@ -401,6 +405,7 @@
// Copy the image file name.
int len = (int) strlen(name) + 1;
_name = new char[len];
+ assert(_name != NULL && "allocation failed");
strncpy(_name, name, len);
// Initialize for a closed file.
_fd = -1;
@@ -473,8 +478,8 @@
// Initialize the module data
ImageModuleData::module_data_name(buffer, _name);
module_data = new ImageModuleData(this, buffer);
- // Successful open.
- return true;
+ // Successful open (if memory allocation succeeded).
+ return module_data != NULL;
}
// Close image file.
@@ -655,6 +660,7 @@
if (!MemoryMapImage) {
// Allocate buffer for compression.
compressed_data = new u1[(u4)compressed_size];
+ assert (compressed_data != NULL && "allocation failed");
// Read bytes from offset beyond the image index.
bool is_read = read_at(compressed_data, compressed_size, _index_size + offset);
assert(is_read && "error reading from image or short read");
--- a/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java Wed Jul 05 21:02:29 2017 +0200
@@ -224,48 +224,75 @@
FileOutputStream f2 = null;
try {
+ boolean forceNullOutputStream = false;
if (redirects == null) {
std_fds = new int[] { -1, -1, -1 };
} else {
std_fds = new int[3];
- if (redirects[0] == Redirect.PIPE)
+ if (redirects[0] == Redirect.PIPE) {
std_fds[0] = -1;
- else if (redirects[0] == Redirect.INHERIT)
+ } else if (redirects[0] == Redirect.INHERIT) {
std_fds[0] = 0;
- else {
+ } else if (redirects[0] instanceof ProcessBuilder.RedirectPipeImpl) {
+ std_fds[0] = fdAccess.get(((ProcessBuilder.RedirectPipeImpl) redirects[0]).getFd());
+ } else {
f0 = new FileInputStream(redirects[0].file());
std_fds[0] = fdAccess.get(f0.getFD());
}
- if (redirects[1] == Redirect.PIPE)
+ if (redirects[1] == Redirect.PIPE) {
std_fds[1] = -1;
- else if (redirects[1] == Redirect.INHERIT)
+ } else if (redirects[1] == Redirect.INHERIT) {
std_fds[1] = 1;
- else {
+ } else if (redirects[1] instanceof ProcessBuilder.RedirectPipeImpl) {
+ std_fds[1] = fdAccess.get(((ProcessBuilder.RedirectPipeImpl) redirects[1]).getFd());
+ // Force getInputStream to return a null stream,
+ // the fd is directly assigned to the next process.
+ forceNullOutputStream = true;
+ } else {
f1 = new FileOutputStream(redirects[1].file(),
redirects[1].append());
std_fds[1] = fdAccess.get(f1.getFD());
}
- if (redirects[2] == Redirect.PIPE)
+ if (redirects[2] == Redirect.PIPE) {
std_fds[2] = -1;
- else if (redirects[2] == Redirect.INHERIT)
+ } else if (redirects[2] == Redirect.INHERIT) {
std_fds[2] = 2;
- else {
+ } else if (redirects[2] instanceof ProcessBuilder.RedirectPipeImpl) {
+ std_fds[2] = fdAccess.get(((ProcessBuilder.RedirectPipeImpl) redirects[2]).getFd());
+ } else {
f2 = new FileOutputStream(redirects[2].file(),
redirects[2].append());
std_fds[2] = fdAccess.get(f2.getFD());
}
}
- return new ProcessImpl
+ Process p = new ProcessImpl
(toCString(cmdarray[0]),
argBlock, args.length,
envBlock, envc[0],
toCString(dir),
std_fds,
+ forceNullOutputStream,
redirectErrorStream);
+ if (redirects != null) {
+ // Copy the fd's if they are to be redirected to another process
+ if (std_fds[0] >= 0 &&
+ redirects[0] instanceof ProcessBuilder.RedirectPipeImpl) {
+ fdAccess.set(((ProcessBuilder.RedirectPipeImpl) redirects[0]).getFd(), std_fds[0]);
+ }
+ if (std_fds[1] >= 0 &&
+ redirects[1] instanceof ProcessBuilder.RedirectPipeImpl) {
+ fdAccess.set(((ProcessBuilder.RedirectPipeImpl) redirects[1]).getFd(), std_fds[1]);
+ }
+ if (std_fds[2] >= 0 &&
+ redirects[2] instanceof ProcessBuilder.RedirectPipeImpl) {
+ fdAccess.set(((ProcessBuilder.RedirectPipeImpl) redirects[2]).getFd(), std_fds[2]);
+ }
+ }
+ return p;
} finally {
// In theory, close() can throw IOException
// (although it is rather unlikely to happen here)
@@ -311,6 +338,7 @@
final byte[] envBlock, final int envc,
final byte[] dir,
final int[] fds,
+ final boolean forceNullOutputStream,
final boolean redirectErrorStream)
throws IOException {
@@ -326,7 +354,7 @@
try {
doPrivileged((PrivilegedExceptionAction<Void>) () -> {
- initStreams(fds);
+ initStreams(fds, forceNullOutputStream);
return null;
});
} catch (PrivilegedActionException ex) {
@@ -340,7 +368,14 @@
return fileDescriptor;
}
- void initStreams(int[] fds) throws IOException {
+ /**
+ * Initialize the streams from the file descriptors.
+ * @param fds array of stdin, stdout, stderr fds
+ * @param forceNullOutputStream true if the stdout is being directed to
+ * a subsequent process. The stdout stream should be a null output stream .
+ * @throws IOException
+ */
+ void initStreams(int[] fds, boolean forceNullOutputStream) throws IOException {
switch (platform) {
case LINUX:
case BSD:
@@ -348,7 +383,7 @@
ProcessBuilder.NullOutputStream.INSTANCE :
new ProcessPipeOutputStream(fds[0]);
- stdout = (fds[1] == -1) ?
+ stdout = (fds[1] == -1 || forceNullOutputStream) ?
ProcessBuilder.NullInputStream.INSTANCE :
new ProcessPipeInputStream(fds[1]);
--- a/jdk/src/java.base/windows/classes/java/lang/ProcessImpl.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.base/windows/classes/java/lang/ProcessImpl.java Wed Jul 05 21:02:29 2017 +0200
@@ -110,38 +110,63 @@
} else {
stdHandles = new long[3];
- if (redirects[0] == Redirect.PIPE)
+ if (redirects[0] == Redirect.PIPE) {
stdHandles[0] = -1L;
- else if (redirects[0] == Redirect.INHERIT)
+ } else if (redirects[0] == Redirect.INHERIT) {
stdHandles[0] = fdAccess.getHandle(FileDescriptor.in);
- else {
+ } else if (redirects[0] instanceof ProcessBuilder.RedirectPipeImpl) {
+ stdHandles[0] = fdAccess.getHandle(((ProcessBuilder.RedirectPipeImpl) redirects[0]).getFd());
+ } else {
f0 = new FileInputStream(redirects[0].file());
stdHandles[0] = fdAccess.getHandle(f0.getFD());
}
- if (redirects[1] == Redirect.PIPE)
+ if (redirects[1] == Redirect.PIPE) {
stdHandles[1] = -1L;
- else if (redirects[1] == Redirect.INHERIT)
+ } else if (redirects[1] == Redirect.INHERIT) {
stdHandles[1] = fdAccess.getHandle(FileDescriptor.out);
- else {
+ } else if (redirects[1] instanceof ProcessBuilder.RedirectPipeImpl) {
+ stdHandles[1] = fdAccess.getHandle(((ProcessBuilder.RedirectPipeImpl) redirects[1]).getFd());
+ } else {
f1 = newFileOutputStream(redirects[1].file(),
redirects[1].append());
stdHandles[1] = fdAccess.getHandle(f1.getFD());
}
- if (redirects[2] == Redirect.PIPE)
+ if (redirects[2] == Redirect.PIPE) {
stdHandles[2] = -1L;
- else if (redirects[2] == Redirect.INHERIT)
+ } else if (redirects[2] == Redirect.INHERIT) {
stdHandles[2] = fdAccess.getHandle(FileDescriptor.err);
- else {
+ } else if (redirects[2] instanceof ProcessBuilder.RedirectPipeImpl) {
+ stdHandles[2] = fdAccess.getHandle(((ProcessBuilder.RedirectPipeImpl) redirects[2]).getFd());
+ } else {
f2 = newFileOutputStream(redirects[2].file(),
redirects[2].append());
stdHandles[2] = fdAccess.getHandle(f2.getFD());
}
}
- return new ProcessImpl(cmdarray, envblock, dir,
+ Process p = new ProcessImpl(cmdarray, envblock, dir,
stdHandles, redirectErrorStream);
+ if (redirects != null) {
+ // Copy the handles's if they are to be redirected to another process
+ if (stdHandles[0] >= 0
+ && redirects[0] instanceof ProcessBuilder.RedirectPipeImpl) {
+ fdAccess.setHandle(((ProcessBuilder.RedirectPipeImpl) redirects[0]).getFd(),
+ stdHandles[0]);
+ }
+ if (stdHandles[1] >= 0
+ && redirects[1] instanceof ProcessBuilder.RedirectPipeImpl) {
+ fdAccess.setHandle(((ProcessBuilder.RedirectPipeImpl) redirects[1]).getFd(),
+ stdHandles[1]);
+ }
+ if (stdHandles[2] >= 0
+ && redirects[2] instanceof ProcessBuilder.RedirectPipeImpl) {
+ fdAccess.setHandle(((ProcessBuilder.RedirectPipeImpl) redirects[2]).getFd(),
+ stdHandles[2]);
+ }
+ }
+ return p;
} finally {
// In theory, close() can throw IOException
// (although it is rather unlikely to happen here)
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m Wed Jul 05 21:02:29 2017 +0200
@@ -42,6 +42,7 @@
-(void) deliverResize: (NSRect) rect;
-(void) resetTrackingArea;
-(void) deliverJavaKeyEventHelper: (NSEvent*) event;
+-(BOOL) isCodePointInUnicodeBlockNeedingIMEvent: (unichar) codePoint;
@end
// Uncomment this line to see fprintfs of each InputMethod API being called on this View
@@ -509,6 +510,14 @@
}
}
+-(BOOL) isCodePointInUnicodeBlockNeedingIMEvent: (unichar) codePoint {
+ if ((codePoint >= 0x3000) && (codePoint <= 0x303F)) {
+ // Code point is in 'CJK Symbols and Punctuation' Unicode block.
+ return YES;
+ }
+ return NO;
+}
+
// NSAccessibility support
- (jobject)awtComponent:(JNIEnv*)env
{
@@ -889,8 +898,14 @@
// (i.e., when the user uses the Character palette or Inkwell), or when the string to insert is a complex
// Unicode value.
NSUInteger utf16Length = [aString lengthOfBytesUsingEncoding:NSUTF16StringEncoding];
+ NSUInteger utf8Length = [aString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+ BOOL aStringIsComplex = NO;
+ if ((utf16Length > 2) ||
+ ((utf8Length > 1) && [self isCodePointInUnicodeBlockNeedingIMEvent:[aString characterAtIndex:0]])) {
+ aStringIsComplex = YES;
+ }
- if ([self hasMarkedText] || !fProcessingKeystroke || (utf16Length > 2)) {
+ if ([self hasMarkedText] || !fProcessingKeystroke || aStringIsComplex) {
JNIEnv *env = [ThreadUtilities getJNIEnv];
static JNF_MEMBER_CACHE(jm_selectPreviousGlyph, jc_CInputMethod, "selectPreviousGlyph", "()V");
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m Wed Jul 05 21:02:29 2017 +0200
@@ -307,6 +307,8 @@
JNFCallVoidMethod(env, jthis,
jm_registerFont, jFontName, jFontFamilyName);
+ (*env)->DeleteLocalRef(env, jFontName);
+ (*env)->DeleteLocalRef(env, jFontFamilyName);
}
JNF_COCOA_EXIT(env);
--- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java Wed Jul 05 21:02:29 2017 +0200
@@ -671,6 +671,40 @@
actions.add(new PrivilegedAction<InputStream>() {
public InputStream run() {
if (System.getProperties().getProperty("os.name")
+ .startsWith("Linux")) {
+
+ File[] systemSoundFontsDir = new File[] {
+ /* Arch, Fedora, Mageia */
+ new File("/usr/share/soundfonts/"),
+ new File("/usr/local/share/soundfonts/"),
+ /* Debian, Gentoo, OpenSUSE, Ubuntu */
+ new File("/usr/share/sounds/sf2/"),
+ new File("/usr/local/share/sounds/sf2/"),
+ };
+
+ /*
+ * Look for a default.sf2
+ */
+ for (File systemSoundFontDir : systemSoundFontsDir) {
+ if (systemSoundFontDir.exists()) {
+ File defaultSoundFont = new File(systemSoundFontDir, "default.sf2");
+ if (defaultSoundFont.exists()) {
+ try {
+ return new FileInputStream(defaultSoundFont);
+ } catch (IOException e) {
+ // continue with lookup
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+ });
+
+ actions.add(new PrivilegedAction<InputStream>() {
+ public InputStream run() {
+ if (System.getProperties().getProperty("os.name")
.startsWith("Windows")) {
File gm_dls = new File(System.getenv("SystemRoot")
+ "\\system32\\drivers\\gm.dls");
--- a/jdk/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java Wed Jul 05 21:02:29 2017 +0200
@@ -325,23 +325,6 @@
};
/**
- * The default strokes for initializing the default focus traversal keys.
- */
- private static final AWTKeyStroke[][] defaultFocusTraversalKeyStrokes = {
- {
- AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, 0, false),
- AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, InputEvent.CTRL_DOWN_MASK | InputEvent.CTRL_MASK, false),
- },
- {
- AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_DOWN_MASK | InputEvent.SHIFT_MASK, false),
- AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,
- InputEvent.SHIFT_DOWN_MASK | InputEvent.SHIFT_MASK | InputEvent.CTRL_DOWN_MASK | InputEvent.CTRL_MASK,
- false),
- },
- {},
- {},
- };
- /**
* The default focus traversal keys. Each array of traversal keys will be
* in effect on all Windows that have no such array of their own explicitly
* set. Each array will also be inherited, recursively, by any child
@@ -431,6 +414,27 @@
* Initializes a KeyboardFocusManager.
*/
public KeyboardFocusManager() {
+ AWTKeyStroke[][] defaultFocusTraversalKeyStrokes = {
+ {
+ AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, 0, false),
+ AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,
+ InputEvent.CTRL_DOWN_MASK |
+ InputEvent.CTRL_MASK, false),
+ },
+ {
+ AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,
+ InputEvent.SHIFT_DOWN_MASK |
+ InputEvent.SHIFT_MASK, false),
+ AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,
+ InputEvent.SHIFT_DOWN_MASK |
+ InputEvent.SHIFT_MASK |
+ InputEvent.CTRL_DOWN_MASK |
+ InputEvent.CTRL_MASK,
+ false),
+ },
+ {},
+ {},
+ };
for (int i = 0; i < TRAVERSAL_KEY_LENGTH; i++) {
Set<AWTKeyStroke> work_set = new HashSet<>();
for (int j = 0; j < defaultFocusTraversalKeyStrokes[i].length; j++) {
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/AbstractRegionPainter.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/AbstractRegionPainter.java Wed Jul 05 21:02:29 2017 +0200
@@ -640,10 +640,6 @@
// check if we can scale to the requested size
Dimension canvas = ctx.canvasSize;
Insets insets = ctx.stretchingInsets;
- if (insets.left + insets.right > w || insets.top + insets.bottom > h) {
- return;
- }
-
if (w <= (canvas.width * ctx.maxHorizontalScaleFactor) && h <= (canvas.height * ctx.maxVerticalScaleFactor)) {
// get image at canvas size
VolatileImage img = getImage(g.getDeviceConfiguration(), c, canvas.width, canvas.height, extendedCacheKeys);
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/skin.laf Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/skin.laf Wed Jul 05 21:02:29 2017 +0200
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
This code is free software; you can redistribute it and/or modify it
@@ -16195,6 +16195,10 @@
<dimension width="150" height="19"/>
</uiProperty>
<uiProperty name="cycleTime" type="INT" value="250"/>
+ <uiProperty name="minBarSize" type="DIMENSION">
+ <dimension width="6" height="6"/>
+ </uiProperty>
+ <uiProperty name="glowWidth" type="INT" value="2"/>
</uiproperties>
</style>
<backgroundStates>
@@ -16351,7 +16355,7 @@
<canvas>
<size width="27" height="19"/>
<nextLayerNameIndex>2</nextLayerNameIndex>
- <stretchingInsets top="5" bottom="5" left="5" right="5"/>
+ <stretchingInsets top="3" bottom="3" left="3" right="3"/>
<layer name="Layer 1">
<opacity>1.0</opacity>
<fillOpacity>1.0</fillOpacity>
@@ -16444,7 +16448,7 @@
<canvas>
<size width="27" height="19"/>
<nextLayerNameIndex>2</nextLayerNameIndex>
- <stretchingInsets top="5" bottom="5" left="5" right="5"/>
+ <stretchingInsets top="3" bottom="3" left="3" right="3"/>
<layer name="Layer 1">
<opacity>1.0</opacity>
<fillOpacity>1.0</fillOpacity>
@@ -16528,7 +16532,7 @@
<canvas>
<size width="30" height="13"/>
<nextLayerNameIndex>2</nextLayerNameIndex>
- <stretchingInsets top="5" bottom="5" left="5" right="5"/>
+ <stretchingInsets top="3" bottom="3" left="3" right="3"/>
<layer name="Layer 1">
<opacity>1.0</opacity>
<fillOpacity>1.0</fillOpacity>
@@ -16619,7 +16623,7 @@
<canvas>
<size width="27" height="19"/>
<nextLayerNameIndex>2</nextLayerNameIndex>
- <stretchingInsets top="5" bottom="5" left="5" right="5"/>
+ <stretchingInsets top="3" bottom="3" left="3" right="3"/>
<layer name="Layer 1">
<opacity>1.0</opacity>
<fillOpacity>1.0</fillOpacity>
@@ -16701,7 +16705,7 @@
<canvas>
<size width="27" height="19"/>
<nextLayerNameIndex>2</nextLayerNameIndex>
- <stretchingInsets top="5" bottom="5" left="5" right="5"/>
+ <stretchingInsets top="3" bottom="3" left="3" right="3"/>
<layer name="Layer 1">
<opacity>1.0</opacity>
<fillOpacity>1.0</fillOpacity>
@@ -16785,7 +16789,7 @@
<canvas>
<size width="30" height="13"/>
<nextLayerNameIndex>2</nextLayerNameIndex>
- <stretchingInsets top="5" bottom="5" left="5" right="5"/>
+ <stretchingInsets top="3" bottom="3" left="3" right="3"/>
<layer name="Layer 1">
<opacity>1.0</opacity>
<fillOpacity>1.0</fillOpacity>
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthProgressBarUI.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthProgressBarUI.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -49,6 +49,8 @@
private boolean paintOutsideClip;
private boolean tileWhenIndeterminate; //whether to tile indeterminate painting
private int tileWidth; //the width of each tile
+ private Dimension minBarSize; // minimal visible bar size
+ private int glowWidth; // Glow around the bar foreground
/**
* Creates a new UI object for the given component.
@@ -114,6 +116,8 @@
tileWidth *= 0.784;
}
}
+ minBarSize = (Dimension)style.get(context, "ProgressBar.minBarSize");
+ glowWidth = style.getInt(context, "ProgressBar.glowWidth", 0);
context.dispose();
}
@@ -258,7 +262,7 @@
if (!SynthLookAndFeel.isLeftToRight(pBar)) {
x = pBar.getWidth() - pBarInsets.right - width
- - progressPadding;
+ - progressPadding - glowWidth;
}
} else { // JProgressBar.VERTICAL
x = pBarInsets.left + progressPadding;
@@ -271,9 +275,9 @@
y = pBar.getHeight() - pBarInsets.bottom - height
- progressPadding;
- // When the progress bar is vertical we always paint
- // from bottom to top, not matter what the component
- // orientation is.
+ if (SynthLookAndFeel.isLeftToRight(pBar)) {
+ y -= glowWidth;
+ }
}
}
} else {
@@ -307,8 +311,11 @@
}
g.setClip(clip);
} else {
- context.getPainter().paintProgressBarForeground(context, g,
- x, y, width, height, pBar.getOrientation());
+ if (minBarSize == null || (width >= minBarSize.width
+ && height >= minBarSize.height)) {
+ context.getPainter().paintProgressBarForeground(context, g,
+ x, y, width, height, pBar.getOrientation());
+ }
}
if (pBar.isStringPainted()) {
--- a/jdk/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java Wed Jul 05 21:02:29 2017 +0200
@@ -42,8 +42,10 @@
private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.focus.KeyboardFocusManagerPeerImpl");
- private static AWTAccessor.KeyboardFocusManagerAccessor kfmAccessor =
- AWTAccessor.getKeyboardFocusManagerAccessor();
+ private static class KfmAccessor {
+ private static AWTAccessor.KeyboardFocusManagerAccessor instance =
+ AWTAccessor.getKeyboardFocusManagerAccessor();
+ }
// The constants are copied from java.awt.KeyboardFocusManager
public static final int SNFH_FAILURE = 0;
@@ -152,12 +154,13 @@
long time,
CausedFocusEvent.Cause cause)
{
- return kfmAccessor.shouldNativelyFocusHeavyweight(
- heavyweight, descendant, temporary, focusedWindowChangeAllowed, time, cause);
+ return KfmAccessor.instance.shouldNativelyFocusHeavyweight(
+ heavyweight, descendant, temporary, focusedWindowChangeAllowed,
+ time, cause);
}
public static void removeLastFocusRequest(Component heavyweight) {
- kfmAccessor.removeLastFocusRequest(heavyweight);
+ KfmAccessor.instance.removeLastFocusRequest(heavyweight);
}
// WARNING: Don't call it on the Toolkit thread.
@@ -167,7 +170,8 @@
boolean focusedWindowChangeAllowed,
long time)
{
- return kfmAccessor.processSynchronousLightweightTransfer(
- heavyweight, descendant, temporary, focusedWindowChangeAllowed, time);
+ return KfmAccessor.instance.processSynchronousLightweightTransfer(
+ heavyweight, descendant, temporary, focusedWindowChangeAllowed,
+ time);
}
}
--- a/jdk/src/java.desktop/share/classes/sun/awt/OSInfo.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/awt/OSInfo.java Wed Jul 05 21:02:29 2017 +0200
@@ -71,7 +71,7 @@
windowsVersionMap.put(WINDOWS_XP.toString(), WINDOWS_XP);
windowsVersionMap.put(WINDOWS_2003.toString(), WINDOWS_2003);
windowsVersionMap.put(WINDOWS_VISTA.toString(), WINDOWS_VISTA);
- windowsVersionMap.put(WINDOWS_VISTA.toString(), WINDOWS_7);
+ windowsVersionMap.put(WINDOWS_7.toString(), WINDOWS_7);
}
private static final PrivilegedAction<OSType> osTypeAction = new PrivilegedAction<OSType>() {
--- a/jdk/src/java.desktop/share/classes/sun/font/FontUtilities.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/font/FontUtilities.java Wed Jul 05 21:02:29 2017 +0200
@@ -72,6 +72,8 @@
static {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @SuppressWarnings("deprecation") // PlatformLogger.setLevel is deprecated.
+ @Override
public Object run() {
String osName = System.getProperty("os.name", "unknownOS");
isSolaris = osName.startsWith("SunOS");
--- a/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java Wed Jul 05 21:02:29 2017 +0200
@@ -631,7 +631,7 @@
String printerName = jobAttributes.getPrinter();
if (printerName != null && printerName != ""
- && !printerName.equals(pServ.getName())) {
+ && pServ != null && !printerName.equals(pServ.getName())) {
// Search for the given printerName in the list of PrintServices
PrintService []services = PrinterJob.lookupPrintServices();
@@ -648,7 +648,7 @@
}
DestinationType dest = jobAttributes.getDestination();
- if (dest == DestinationType.FILE &&
+ if (dest == DestinationType.FILE && pServ != null &&
pServ.isAttributeCategorySupported(Destination.class)) {
String fileName = jobAttributes.getFileName();
--- a/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c Wed Jul 05 21:02:29 2017 +0200
@@ -103,7 +103,6 @@
}
static void freeNativeResources(JNIEnv *env, FTScalerInfo* scalerInfo) {
- void *stream;
if (scalerInfo == NULL)
return;
--- a/jdk/src/java.desktop/unix/classes/sun/print/IPPPrintService.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.desktop/unix/classes/sun/print/IPPPrintService.java Wed Jul 05 21:02:29 2017 +0200
@@ -321,7 +321,11 @@
if ((name == null) || (url == null)){
throw new IllegalArgumentException("null uri or printer name");
}
- printer = name;
+ try {
+ printer = java.net.URLDecoder.decode(name, "UTF-8");
+ } catch (java.io.UnsupportedEncodingException e) {
+ printer = name;
+ }
supportedDocFlavors = null;
supportedCats = null;
mediaSizeNames = null;
@@ -351,7 +355,11 @@
if ((name == null) || (uriStr == null)){
throw new IllegalArgumentException("null uri or printer name");
}
- printer = name;
+ try {
+ printer = java.net.URLDecoder.decode(name, "UTF-8");
+ } catch (java.io.UnsupportedEncodingException e) {
+ printer = name;
+ }
supportedDocFlavors = null;
supportedCats = null;
mediaSizeNames = null;
--- a/jdk/src/java.desktop/unix/native/common/awt/fontpath.c Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.desktop/unix/native/common/awt/fontpath.c Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -178,6 +178,7 @@
"()Z");
JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);
isLocal = (*env)->CallBooleanMethod(env, ge, isDisplayLocal);
+ JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);
} else {
isLocal = True;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.logging/share/classes/META-INF/services/jdk.internal.logger.DefaultLoggerFinder Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,1 @@
+sun.util.logging.internal.LoggingProviderImpl
--- a/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java Wed Jul 05 21:02:29 2017 +0200
@@ -43,6 +43,7 @@
import jdk.internal.misc.JavaAWTAccess;
import jdk.internal.misc.SharedSecrets;
import sun.misc.ManagedLocalsThread;
+import sun.util.logging.internal.LoggingProviderImpl;
/**
* There is a single global LogManager object that is used to
@@ -436,7 +437,8 @@
readConfiguration();
// Platform loggers begin to delegate to java.util.logging.Logger
- sun.util.logging.PlatformLogger.redirectPlatformLoggers();
+ jdk.internal.logger.BootstrapLogger.redirectTemporaryLoggers();
+
} catch (Exception ex) {
assert false : "Exception raised while reading logging configuration: " + ex;
}
@@ -1481,7 +1483,7 @@
* <p>
* Any {@linkplain #addConfigurationListener registered configuration
* listener} will be invoked after the properties are read.
- * <p>
+ *
* @apiNote This {@code readConfiguration} method should only be used for
* initializing the configuration during LogManager initialization or
* used with the "java.util.logging.config.class" property.
@@ -2363,7 +2365,8 @@
}
}
- static final Permission controlPermission = new LoggingPermission("control", null);
+ static final Permission controlPermission =
+ new LoggingPermission("control", null);
void checkPermission() {
SecurityManager sm = System.getSecurityManager();
@@ -2607,4 +2610,69 @@
if (t instanceof RuntimeException) throw (RuntimeException)t;
}
+ /**
+ * This class allows the {@link LoggingProviderImpl} to demand loggers on
+ * behalf of system and application classes.
+ */
+ private static final class LoggingProviderAccess
+ implements LoggingProviderImpl.LogManagerAccess,
+ PrivilegedAction<Void> {
+
+ private LoggingProviderAccess() {
+ }
+
+ /**
+ * Demands a logger on behalf of the given {@code caller}.
+ * <p>
+ * If a named logger suitable for the given caller is found
+ * returns it.
+ * Otherwise, creates a new logger suitable for the given caller.
+ *
+ * @param name The logger name.
+ * @param caller The caller on which behalf the logger is created/retrieved.
+ * @return A logger for the given {@code caller}.
+ *
+ * @throws NullPointerException if {@code name} is {@code null}
+ * or {@code caller} is {@code null}.
+ * @throws IllegalArgumentException if {@code manager} is not the default
+ * LogManager.
+ * @throws SecurityException if a security manager is present and the
+ * calling code doesn't have the
+ * {@link LoggingPermission LoggingPermission("demandLogger", null)}.
+ */
+ @Override
+ public Logger demandLoggerFor(LogManager manager, String name, /* Module */ Class<?> caller) {
+ if (manager != getLogManager()) {
+ // having LogManager as parameter just ensures that the
+ // caller will have initialized the LogManager before reaching
+ // here.
+ throw new IllegalArgumentException("manager");
+ }
+ Objects.requireNonNull(name);
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(controlPermission);
+ }
+ if (caller.getClassLoader() == null) {
+ return manager.demandSystemLogger(name,
+ Logger.SYSTEM_LOGGER_RB_NAME, caller);
+ } else {
+ return manager.demandLogger(name, null, caller);
+ }
+ }
+
+ @Override
+ public Void run() {
+ LoggingProviderImpl.setLogManagerAccess(INSTANCE);
+ return null;
+ }
+
+ static final LoggingProviderAccess INSTANCE = new LoggingProviderAccess();
+ }
+
+ static {
+ AccessController.doPrivileged(LoggingProviderAccess.INSTANCE, null,
+ controlPermission);
+ }
+
}
--- a/jdk/src/java.logging/share/classes/java/util/logging/LogRecord.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.logging/share/classes/java/util/logging/LogRecord.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
import jdk.internal.misc.JavaLangAccess;
import jdk.internal.misc.SharedSecrets;
+import static jdk.internal.logger.SimpleConsoleLogger.skipLoggingFrame;
/**
* LogRecord objects are used to pass logging requests between
@@ -637,6 +638,27 @@
}
// Private method to infer the caller's class and method names
+ //
+ // Note:
+ // For testing purposes - it is possible to customize the process
+ // by which LogRecord will infer the source class name and source method name
+ // when analyzing the call stack.
+ // <p>
+ // The system property {@code jdk.logger.packages} can define a comma separated
+ // list of strings corresponding to additional package name prefixes that
+ // should be ignored when trying to infer the source caller class name.
+ // Those stack frames whose {@linkplain StackTraceElement#getClassName()
+ // declaring class name} start with one such prefix will be ignored.
+ // <p>
+ // This is primarily useful when providing utility logging classes wrapping
+ // a logger instance, as it makes it possible to instruct LogRecord to skip
+ // those utility frames when inferring the caller source class name.
+ // <p>
+ // The {@code jdk.logger.packages} system property is consulted only once.
+ // <p>
+ // This property is not standard, implementation specific, and yet
+ // undocumented (and thus subject to changes without notice).
+ //
private void inferCaller() {
needToInferCaller = false;
JavaLangAccess access = SharedSecrets.getJavaLangAccess();
@@ -658,8 +680,8 @@
}
} else {
if (!isLoggerImpl) {
- // skip reflection call
- if (!cname.startsWith("java.lang.reflect.") && !cname.startsWith("sun.reflect.")) {
+ // skip logging/logger infrastructure and reflection calls
+ if (!skipLoggingFrame(cname)) {
// We've found the relevant frame.
setSourceClassName(cname);
setSourceMethodName(frame.getMethodName());
@@ -675,7 +697,6 @@
private boolean isLoggerImplFrame(String cname) {
// the log record could be created for a platform logger
return (cname.equals("java.util.logging.Logger") ||
- cname.startsWith("java.util.logging.LoggingProxyImpl") ||
- cname.startsWith("sun.util.logging."));
+ cname.startsWith("sun.util.logging.PlatformLogger"));
}
}
--- a/jdk/src/java.logging/share/classes/java/util/logging/Logger.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.logging/share/classes/java/util/logging/Logger.java Wed Jul 05 21:02:29 2017 +0200
@@ -447,8 +447,7 @@
private static Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
LogManager manager = LogManager.getLogManager();
- SecurityManager sm = System.getSecurityManager();
- if (sm != null && !SystemLoggerHelper.disableCallerCheck) {
+ if (!SystemLoggerHelper.disableCallerCheck) {
if (caller.getClassLoader() == null) {
return manager.demandSystemLogger(name, resourceBundleName, caller);
}
@@ -1254,14 +1253,14 @@
* with an optional list of message parameters.
* <p>
* If the logger is currently enabled for the given message
- * level then a corresponding LogRecord is created and forwarded
- * to all the registered output Handler objects.
+ * {@code level} then a corresponding {@code LogRecord} is created and
+ * forwarded to all the registered output {@code Handler} objects.
* <p>
* The {@code msg} string is localized using the given resource bundle.
* If the resource bundle is {@code null}, then the {@code msg} string is not
* localized.
*
- * @param level One of the message level identifiers, e.g., SEVERE
+ * @param level One of the message level identifiers, e.g., {@code SEVERE}
* @param sourceClass Name of the class that issued the logging request
* @param sourceMethod Name of the method that issued the logging request
* @param bundle Resource bundle to localize {@code msg},
@@ -1285,6 +1284,36 @@
}
/**
+ * Log a message, specifying source class, method, and resource bundle,
+ * with an optional list of message parameters.
+ * <p>
+ * If the logger is currently enabled for the given message
+ * {@code level} then a corresponding {@code LogRecord} is created
+ * and forwarded to all the registered output {@code Handler} objects.
+ * <p>
+ * The {@code msg} string is localized using the given resource bundle.
+ * If the resource bundle is {@code null}, then the {@code msg} string is not
+ * localized.
+ * <p>
+ * @param level One of the message level identifiers, e.g., {@code SEVERE}
+ * @param bundle Resource bundle to localize {@code msg};
+ * can be {@code null}.
+ * @param msg The string message (or a key in the message catalog)
+ * @param params Parameters to the message (optional, may be none).
+ * @since 1.9
+ */
+ public void logrb(Level level, ResourceBundle bundle, String msg, Object... params) {
+ if (!isLoggable(level)) {
+ return;
+ }
+ LogRecord lr = new LogRecord(level, msg);
+ if (params != null && params.length != 0) {
+ lr.setParameters(params);
+ }
+ doLog(lr, bundle);
+ }
+
+ /**
* Log a message, specifying source class, method, and resource bundle name,
* with associated Throwable information.
* <p>
@@ -1330,19 +1359,20 @@
* with associated Throwable information.
* <p>
* If the logger is currently enabled for the given message
- * level then the given arguments are stored in a LogRecord
+ * {@code level} then the given arguments are stored in a {@code LogRecord}
* which is forwarded to all registered output handlers.
* <p>
* The {@code msg} string is localized using the given resource bundle.
* If the resource bundle is {@code null}, then the {@code msg} string is not
* localized.
* <p>
- * Note that the thrown argument is stored in the LogRecord thrown
- * property, rather than the LogRecord parameters property. Thus it is
- * processed specially by output Formatters and is not treated
- * as a formatting parameter to the LogRecord message property.
+ * Note that the {@code thrown} argument is stored in the {@code LogRecord}
+ * {@code thrown} property, rather than the {@code LogRecord}
+ * {@code parameters} property. Thus it is
+ * processed specially by output {@code Formatter} objects and is not treated
+ * as a formatting parameter to the {@code LogRecord} {@code message} property.
*
- * @param level One of the message level identifiers, e.g., SEVERE
+ * @param level One of the message level identifiers, e.g., {@code SEVERE}
* @param sourceClass Name of the class that issued the logging request
* @param sourceMethod Name of the method that issued the logging request
* @param bundle Resource bundle to localize {@code msg},
@@ -1363,6 +1393,42 @@
doLog(lr, bundle);
}
+ /**
+ * Log a message, specifying source class, method, and resource bundle,
+ * with associated Throwable information.
+ * <p>
+ * If the logger is currently enabled for the given message
+ * {@code level} then the given arguments are stored in a {@code LogRecord}
+ * which is forwarded to all registered output handlers.
+ * <p>
+ * The {@code msg} string is localized using the given resource bundle.
+ * If the resource bundle is {@code null}, then the {@code msg} string is not
+ * localized.
+ * <p>
+ * Note that the {@code thrown} argument is stored in the {@code LogRecord}
+ * {@code thrown} property, rather than the {@code LogRecord}
+ * {@code parameters} property. Thus it is
+ * processed specially by output {@code Formatter} objects and is not treated
+ * as a formatting parameter to the {@code LogRecord} {@code message}
+ * property.
+ * <p>
+ * @param level One of the message level identifiers, e.g., {@code SEVERE}
+ * @param bundle Resource bundle to localize {@code msg};
+ * can be {@code null}.
+ * @param msg The string message (or a key in the message catalog)
+ * @param thrown Throwable associated with the log message.
+ * @since 1.9
+ */
+ public void logrb(Level level, ResourceBundle bundle, String msg,
+ Throwable thrown) {
+ if (!isLoggable(level)) {
+ return;
+ }
+ LogRecord lr = new LogRecord(level, msg);
+ lr.setThrown(thrown);
+ doLog(lr, bundle);
+ }
+
//======================================================================
// Start of convenience methods for logging method entries and returns.
//======================================================================
--- a/jdk/src/java.logging/share/classes/java/util/logging/LoggingProxyImpl.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-/*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package java.util.logging;
-
-import sun.util.logging.LoggingProxy;
-
-/**
- * Implementation of LoggingProxy when java.util.logging classes exist.
- */
-class LoggingProxyImpl implements LoggingProxy {
- static final LoggingProxy INSTANCE = new LoggingProxyImpl();
-
- private LoggingProxyImpl() { }
-
- @Override
- public Object getLogger(String name) {
- // always create a platform logger with the resource bundle name
- return Logger.getPlatformLogger(name);
- }
-
- @Override
- public Object getLevel(Object logger) {
- return ((Logger) logger).getLevel();
- }
-
- @Override
- public void setLevel(Object logger, Object newLevel) {
- ((Logger) logger).setLevel((Level) newLevel);
- }
-
- @Override
- public boolean isLoggable(Object logger, Object level) {
- return ((Logger) logger).isLoggable((Level) level);
- }
-
- @Override
- public void log(Object logger, Object level, String msg) {
- ((Logger) logger).log((Level) level, msg);
- }
-
- @Override
- public void log(Object logger, Object level, String msg, Throwable t) {
- ((Logger) logger).log((Level) level, msg, t);
- }
-
- @Override
- public void log(Object logger, Object level, String msg, Object... params) {
- ((Logger) logger).log((Level) level, msg, params);
- }
-
- @Override
- public java.util.List<String> getLoggerNames() {
- return LogManager.getLoggingMXBean().getLoggerNames();
- }
-
- @Override
- public String getLoggerLevel(String loggerName) {
- return LogManager.getLoggingMXBean().getLoggerLevel(loggerName);
- }
-
- @Override
- public void setLoggerLevel(String loggerName, String levelName) {
- LogManager.getLoggingMXBean().setLoggerLevel(loggerName, levelName);
- }
-
- @Override
- public String getParentLoggerName(String loggerName) {
- return LogManager.getLoggingMXBean().getParentLoggerName(loggerName);
- }
-
- @Override
- public Object parseLevel(String levelName) {
- Level level = Level.findLevel(levelName);
- if (level == null) {
- throw new IllegalArgumentException("Unknown level \"" + levelName + "\"");
- }
- return level;
- }
-
- @Override
- public String getLevelName(Object level) {
- return ((Level) level).getLevelName();
- }
-
- @Override
- public int getLevelValue(Object level) {
- return ((Level) level).intValue();
- }
-
- @Override
- public String getProperty(String key) {
- return LogManager.getLogManager().getProperty(key);
- }
-}
--- a/jdk/src/java.logging/share/classes/java/util/logging/SimpleFormatter.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.logging/share/classes/java/util/logging/SimpleFormatter.java Wed Jul 05 21:02:29 2017 +0200
@@ -27,10 +27,9 @@
package java.util.logging;
import java.io.*;
-import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
-import sun.util.logging.LoggingSupport;
+import jdk.internal.logger.SimpleConsoleLogger;
/**
* Print a brief summary of the {@code LogRecord} in a human readable
@@ -60,8 +59,12 @@
public class SimpleFormatter extends Formatter {
// format string for printing the log record
- private final String format = LoggingSupport.getSimpleFormat();
- private final ZoneId zoneId = ZoneId.systemDefault();
+ static String getLoggingProperty(String name) {
+ return LogManager.getLogManager().getProperty(name);
+ }
+
+ private final String format =
+ SimpleConsoleLogger.getSimpleFormat(SimpleFormatter::getLoggingProperty);
/**
* Format the given LogRecord.
@@ -152,7 +155,7 @@
@Override
public synchronized String format(LogRecord record) {
ZonedDateTime zdt = ZonedDateTime.ofInstant(
- record.getInstant(), zoneId);
+ record.getInstant(), ZoneId.systemDefault());
String source;
if (record.getSourceClassName() != null) {
source = record.getSourceClassName();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.logging/share/classes/sun/util/logging/internal/LoggingProviderImpl.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package sun.util.logging.internal;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ResourceBundle;
+import java.util.function.Supplier;
+import java.lang.System.LoggerFinder;
+import java.lang.System.Logger;
+import java.util.Objects;
+import java.util.logging.LogManager;
+import jdk.internal.logger.DefaultLoggerFinder;
+import java.util.logging.LoggingPermission;
+import sun.util.logging.PlatformLogger;
+import sun.util.logging.PlatformLogger.ConfigurableBridge.LoggerConfiguration;
+
+/**
+ * This {@code LoggingProviderImpl} is the JDK internal implementation of the
+ * {@link jdk.internal.logger.DefaultLoggerFinder} which is used by
+ * the default implementation of the {@link Logger}
+ * when no {@link LoggerFinder} is found
+ * and {@code java.util.logging} is present.
+ * When {@code java.util.logging} is present, the {@code LoggingProviderImpl}
+ * is {@linkplain java.util.ServiceLoader#loadInstalled(Class) installed} as
+ * an internal service provider, making it possible to use {@code java.util.logging}
+ * as the backend for loggers returned by the default LoggerFinder implementation.
+ * <p>
+ * This implementation of {@link DefaultLoggerFinder} returns instances of
+ * {@link java.lang.System.Logger} which
+ * delegate to a wrapped instance of {@link java.util.logging.Logger
+ * java.util.logging.Logger}.
+ * <br>
+ * Loggers returned by this class can therefore be configured by accessing
+ * their wrapped implementation through the regular {@code java.util.logging}
+ * APIs - such as {@link java.util.logging.LogManager java.util.logging.LogManager}
+ * and {@link java.util.logging.Logger java.util.logging.Logger}.
+ *
+ * @apiNote Programmers are not expected to call this class directly.
+ * Instead they should rely on the static methods defined by
+ * {@link java.lang.System java.lang.System}.
+ * <p>
+ * To replace this default
+ * {@code java.util.logging} backend, an application is expected to install
+ * its own {@link java.lang.System.LoggerFinder}.
+ *
+ * @see java.lang.System.Logger
+ * @see java.lang.System.LoggerFinder
+ * @see sun.util.logging.PlatformLogger.Bridge
+ * @see java.lang.System
+ * @see jdk.internal.logger
+ * @see jdk.internal.logger
+ *
+ */
+public final class LoggingProviderImpl extends DefaultLoggerFinder {
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+ private static final LoggingPermission LOGGING_CONTROL_PERMISSION =
+ new LoggingPermission("control", null);
+
+ /**
+ * Creates a new instance of LoggingProviderImpl.
+ * @throws SecurityException if the calling code does not have the
+ * {@code RuntimePermission("loggerFinder")}.
+ */
+ public LoggingProviderImpl() {
+ }
+
+ /**
+ * A logger that delegates to a java.util.logging.Logger delegate.
+ */
+ static final class JULWrapper extends LoggerConfiguration
+ implements System.Logger, PlatformLogger.Bridge,
+ PlatformLogger.ConfigurableBridge {
+
+
+ private static final java.util.logging.Level[] spi2JulLevelMapping = {
+ java.util.logging.Level.ALL, // mapped from ALL
+ java.util.logging.Level.FINER, // mapped from TRACE
+ java.util.logging.Level.FINE, // mapped from DEBUG
+ java.util.logging.Level.INFO, // mapped from INFO
+ java.util.logging.Level.WARNING, // mapped from WARNING
+ java.util.logging.Level.SEVERE, // mapped from ERROR
+ java.util.logging.Level.OFF // mapped from OFF
+ };
+
+ private static final java.util.logging.Level[] platform2JulLevelMapping = {
+ java.util.logging.Level.ALL, // mapped from ALL
+ java.util.logging.Level.FINEST, // mapped from FINEST
+ java.util.logging.Level.FINER, // mapped from FINER
+ java.util.logging.Level.FINE, // mapped from FINE
+ java.util.logging.Level.CONFIG, // mapped from CONFIG
+ java.util.logging.Level.INFO, // mapped from INFO
+ java.util.logging.Level.WARNING, // mapped from WARNING
+ java.util.logging.Level.SEVERE, // mapped from SEVERE
+ java.util.logging.Level.OFF // mapped from OFF
+ };
+
+ private final java.util.logging.Logger julLogger;
+
+
+ private JULWrapper(java.util.logging.Logger logger) {
+ this.julLogger = logger;
+ }
+
+ @Override
+ public String getName() {
+ return julLogger.getName();
+ }
+ @Override
+ public void log(sun.util.logging.PlatformLogger.Level level, String msg, Throwable throwable) {
+ julLogger.log(toJUL(level), msg, throwable);
+ }
+
+ @Override
+ public void log(sun.util.logging.PlatformLogger.Level level, String format, Object... params) {
+ julLogger.log(toJUL(level), format, params);
+ }
+
+ @Override
+ public void log(sun.util.logging.PlatformLogger.Level level, String msg) {
+ julLogger.log(toJUL(level), msg);
+ }
+
+ @Override
+ public void log(sun.util.logging.PlatformLogger.Level level, Supplier<String> msgSuppier) {
+ julLogger.log(toJUL(level), msgSuppier);
+ }
+
+ @Override
+ public void log(sun.util.logging.PlatformLogger.Level level, Throwable thrown, Supplier<String> msgSuppier) {
+ julLogger.log(toJUL(level), thrown, msgSuppier);
+ }
+
+ @Override
+ public void logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle, String key, Throwable throwable) {
+ julLogger.logrb(toJUL(level), bundle, key, throwable);
+ }
+
+ @Override
+ public void logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle, String key, Object... params) {
+ julLogger.logrb(toJUL(level), bundle, key, params);
+ }
+
+ @Override
+ public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, String msg) {
+ julLogger.logp(toJUL(level), sourceClass, sourceMethod, msg);
+ }
+
+ @Override
+ public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,
+ Supplier<String> msgSupplier) {
+ julLogger.logp(toJUL(level), sourceClass, sourceMethod, msgSupplier);
+ }
+
+ @Override
+ public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,
+ String msg, Object... params) {
+ julLogger.logp(toJUL(level), sourceClass, sourceMethod, msg, params);
+ }
+
+ @Override
+ public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,
+ String msg, Throwable thrown) {
+ julLogger.logp(toJUL(level), sourceClass, sourceMethod, msg, thrown);
+ }
+
+ @Override
+ public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,
+ Throwable thrown, Supplier<String> msgSupplier) {
+ julLogger.logp(toJUL(level), sourceClass, sourceMethod,
+ thrown, msgSupplier);
+ }
+
+ @Override
+ public void logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,
+ ResourceBundle bundle, String key, Object... params) {
+ julLogger.logrb(toJUL(level), sourceClass, sourceMethod,
+ bundle, key, params);
+ }
+
+ @Override
+ public void logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,
+ ResourceBundle bundle, String key, Throwable thrown) {
+ julLogger.logrb(toJUL(level), sourceClass, sourceMethod,
+ bundle, key, thrown);
+ }
+
+ @Override
+ public boolean isLoggable(sun.util.logging.PlatformLogger.Level level) {
+ return julLogger.isLoggable(toJUL(level));
+ }
+
+ // -----------------------------------------------------------------
+ // Generic methods taking a Level as parameter
+ // -----------------------------------------------------------------
+
+
+ @Override
+ public boolean isLoggable(Level level) {
+ return julLogger.isLoggable(toJUL(level));
+ }
+
+ @Override
+ public void log(Level level, String msg) {
+ julLogger.log(toJUL(level), msg);
+ }
+
+ @Override
+ public void log(Level level,
+ Supplier<String> msgSupplier) {
+ // We need to check for null here to satisfy the contract
+ // of System.Logger - because the underlying implementation
+ // of julLogger will check for it only if the level is
+ // loggable
+ Objects.requireNonNull(msgSupplier);
+ julLogger.log(toJUL(level), msgSupplier);
+ }
+
+ @Override
+ public void log(Level level, Object obj) {
+ // We need to check for null here to satisfy the contract
+ // of System.Logger - because the underlying implementation
+ // of julLogger will check for it only if the level is
+ // loggable
+ Objects.requireNonNull(obj);
+ julLogger.log(toJUL(level), () -> obj.toString());
+ }
+
+ @Override
+ public void log(Level level,
+ String msg, Throwable thrown) {
+ julLogger.log(toJUL(level), msg, thrown);
+ }
+
+ @Override
+ public void log(Level level, Supplier<String> msgSupplier,
+ Throwable thrown) {
+ // We need to check for null here to satisfy the contract
+ // of System.Logger - because the underlying implementation
+ // of julLogger will check for it only if the level is
+ // loggable
+ Objects.requireNonNull(msgSupplier);
+ julLogger.log(toJUL(level), thrown, msgSupplier);
+ }
+
+ @Override
+ public void log(Level level,
+ String format, Object... params) {
+ julLogger.log(toJUL(level), format, params);
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle,
+ String key, Throwable thrown) {
+ julLogger.logrb(toJUL(level), bundle, key, thrown);
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle,
+ String format, Object... params) {
+ julLogger.logrb(toJUL(level), bundle, format, params);
+ }
+
+ static java.util.logging.Level toJUL(Level level) {
+ if (level == null) return null;
+ assert level.ordinal() < spi2JulLevelMapping.length;
+ return spi2JulLevelMapping[level.ordinal()];
+ }
+
+ // ---------------------------------------------------------
+ // Methods from PlatformLogger.Bridge
+ // ---------------------------------------------------------
+
+ @Override
+ public boolean isEnabled() {
+ return julLogger.getLevel() != java.util.logging.Level.OFF;
+ }
+
+ @Override
+ public PlatformLogger.Level getPlatformLevel() {
+ final java.util.logging.Level javaLevel = julLogger.getLevel();
+ if (javaLevel == null) return null;
+ try {
+ return PlatformLogger.Level.valueOf(javaLevel.getName());
+ } catch (IllegalArgumentException e) {
+ return PlatformLogger.Level.valueOf(javaLevel.intValue());
+ }
+ }
+
+ @Override
+ public void setPlatformLevel(PlatformLogger.Level level) {
+ // null is allowed here
+ julLogger.setLevel(toJUL(level));
+ }
+
+ @Override
+ public LoggerConfiguration getLoggerConfiguration() {
+ return this;
+ }
+
+ static java.util.logging.Level toJUL(PlatformLogger.Level level) {
+ // The caller will throw if null is invalid in its context.
+ // There's at least one case where a null level is valid.
+ if (level == null) return null;
+ assert level.ordinal() < platform2JulLevelMapping.length;
+ return platform2JulLevelMapping[level.ordinal()];
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return (obj instanceof JULWrapper)
+ && obj.getClass() == this.getClass()
+ && ((JULWrapper)obj).julLogger == this.julLogger;
+ }
+
+ @Override
+ public int hashCode() {
+ return julLogger.hashCode();
+ }
+
+ // A JULWrapper is just a stateless thin shell over a JUL logger - so
+ // for a given JUL logger, we could always return the same wrapper.
+ //
+ // This is an optimization which may - or may not - be worth the
+ // trouble: if many classes use the same logger, and if each class
+ // keeps a reference to that logger, then caching the wrapper will
+ // be worthwhile. Otherwise, if each logger is only referred once,
+ // then the cache will eat up more memory than would be necessary...
+ //
+ // Here is an example of how we could implement JULWrapper.of(...)
+ // if we wanted to create at most one wrapper instance for each logger
+ // instance:
+ //
+ // static final WeakHashMap<JULWrapper, WeakReference<JULWrapper>>
+ // wrappers = new WeakHashMap<>();
+ //
+ // static JULWrapper of(java.util.logging.Logger logger) {
+ //
+ // // First access without synchronizing
+ // final JULWrapper candidate = new JULWrapper(logger);
+ // WeakReference<JULWrapper> ref = wrappers.get(candidate);
+ // JULWrapper found = ref.get();
+ //
+ // // OK - we found it - lets return it.
+ // if (found != null) return found;
+ //
+ // // Not found. Need to synchronize.
+ // synchronized (wrappers) {
+ // ref = wrappers.get(candidate);
+ // found = ref.get();
+ // if (found == null) {
+ // wrappers.put(candidate, new WeakReference<>(candidate));
+ // found = candidate;
+ // }
+ // }
+ // assert found != null;
+ // return found;
+ // }
+ //
+ // But given that it may end up eating more memory in the nominal case
+ // (where each class that does logging has its own logger with the
+ // class name as logger name and stashes that logger away in a static
+ // field, thus making the cache redundant - as only one wrapper will
+ // ever be created anyway) - then we will simply return a new wrapper
+ // for each invocation of JULWrapper.of(...) - which may
+ // still prove more efficient in terms of memory consumption...
+ //
+ static JULWrapper of(java.util.logging.Logger logger) {
+ return new JULWrapper(logger);
+ }
+
+
+ }
+
+ /**
+ * Creates a java.util.logging.Logger for the given caller.
+ * @param name the logger name.
+ * @param caller the caller for which the logger should be created.
+ * @return a Logger suitable for use in the given caller.
+ */
+ private static java.util.logging.Logger demandJULLoggerFor(final String name,
+ /* Module */
+ final Class<?> caller) {
+ final LogManager manager = LogManager.getLogManager();
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm == null) {
+ return logManagerAccess.demandLoggerFor(manager, name, caller);
+ } else {
+ final PrivilegedAction<java.util.logging.Logger> pa =
+ () -> logManagerAccess.demandLoggerFor(manager, name, caller);
+ return AccessController.doPrivileged(pa, null, LOGGING_CONTROL_PERMISSION);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @apiNote The logger returned by this method can be configured through
+ * its {@linkplain java.util.logging.LogManager#getLogger(String)
+ * corresponding java.util.logging.Logger backend}.
+ *
+ * @return {@inheritDoc}
+ * @throws SecurityException if the calling code doesn't have the
+ * {@code RuntimePermission("loggerFinder")}.
+ */
+ @Override
+ protected Logger demandLoggerFor(String name, /* Module */ Class<?> caller) {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGERFINDER_PERMISSION);
+ }
+ return JULWrapper.of(demandJULLoggerFor(name,caller));
+ }
+
+ public static interface LogManagerAccess {
+ java.util.logging.Logger demandLoggerFor(LogManager manager,
+ String name, /* Module */ Class<?> caller);
+ }
+
+ // Hook for tests
+ public static LogManagerAccess getLogManagerAccess() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGING_CONTROL_PERMISSION);
+ }
+ // Triggers initialization of accessJulLogger if not set.
+ if (logManagerAccess == null) LogManager.getLogManager();
+ return logManagerAccess;
+ }
+
+
+ private static volatile LogManagerAccess logManagerAccess;
+ public static void setLogManagerAccess(LogManagerAccess accesLoggers) {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGING_CONTROL_PERMISSION);
+ }
+ logManagerAccess = accesLoggers;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.logging/share/classes/sun/util/logging/internal/package-info.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * <p>
+ * <b>[JDK INTERNAL]</b>
+ * The {@code sun.util.logging.internal} package defines an internal
+ * implementation of the {@link jdk.internal.logger.DefaultLoggerFinder} which
+ * provides an extension of the {@link java.lang.System.Logger System.Logger}
+ * interface making it easy to bridge from {@link java.util.logging};
+ * the JDK default implementation of the LoggerFinder will return loggers
+ * implementing this extension when {@code java.util.logging} is present.
+ * </p>
+ * <p>
+ * When {@code java.util.logging} is present, Logger instances returned by
+ * the JDK default implementation of the LoggerFinder
+ * wrap an instance of {@link java.util.logging.Logger java.util.logging.Logger}
+ * and implement the {@link
+ * sun.util.logging.PlatformLogger.Bridge PlatformLogger.Bridge}
+ * extension, overriding all the methods defined in
+ * that extension in order to call the corresponding methods on their wrapped
+ * {@linkplain java.util.logging.Logger backend Logger} instance.
+ * <p>
+ * <br>
+ * @see java.lang.System.LoggerFinder
+ * @see java.lang.System.Logger
+ * @see sun.util.logging.PlatformLogger
+ * @see sun.util.logging.PlatformLogger.Bridge
+ * @see jdk.internal.logger
+ *
+ * @since 1.9
+ */
+package sun.util.logging.internal;
--- a/jdk/src/java.management/share/classes/java/lang/management/DefaultPlatformMBeanProvider.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.management/share/classes/java/lang/management/DefaultPlatformMBeanProvider.java Wed Jul 05 21:02:29 2017 +0200
@@ -355,36 +355,38 @@
}
});
- /**
- * Logging facility.
- */
- initMBeanList.add(new PlatformComponent<PlatformLoggingMXBean>() {
- private final Set<String> platformLoggingMXBeanInterfaceNames
+ if (ManagementFactoryHelper.isPlatformLoggingMXBeanAvailable()) {
+ /**
+ * Logging facility.
+ */
+ initMBeanList.add(new PlatformComponent<PlatformLoggingMXBean>() {
+ private final Set<String> platformLoggingMXBeanInterfaceNames
= Collections.unmodifiableSet(Collections.singleton(
"java.lang.management.PlatformLoggingMXBean"));
- @Override
- public Set<Class<? extends PlatformLoggingMXBean>> mbeanInterfaces() {
- return Collections.singleton(PlatformLoggingMXBean.class);
- }
+ @Override
+ public Set<Class<? extends PlatformLoggingMXBean>> mbeanInterfaces() {
+ return Collections.singleton(PlatformLoggingMXBean.class);
+ }
- @Override
- public Set<String> mbeanInterfaceNames() {
- return platformLoggingMXBeanInterfaceNames;
- }
+ @Override
+ public Set<String> mbeanInterfaceNames() {
+ return platformLoggingMXBeanInterfaceNames;
+ }
- @Override
- public String getObjectNamePattern() {
- return "java.util.logging:type=Logging";
- }
+ @Override
+ public String getObjectNamePattern() {
+ return "java.util.logging:type=Logging";
+ }
- @Override
- public Map<String, PlatformLoggingMXBean> nameToMBeanMap() {
- return Collections.singletonMap(
+ @Override
+ public Map<String, PlatformLoggingMXBean> nameToMBeanMap() {
+ return Collections.singletonMap(
"java.util.logging:type=Logging",
ManagementFactoryHelper.getPlatformLoggingMXBean());
- }
- });
+ }
+ });
+ }
/**
* Buffer pools.
--- a/jdk/src/java.management/share/classes/sun/management/ManagementFactoryHelper.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/java.management/share/classes/sun/management/ManagementFactoryHelper.java Wed Jul 05 21:02:29 2017 +0200
@@ -39,10 +39,14 @@
import jdk.internal.misc.JavaNioAccess;
import jdk.internal.misc.SharedSecrets;
-import sun.util.logging.LoggingSupport;
+
import java.util.ArrayList;
import java.util.List;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.security.PrivilegedAction;
+
/**
* ManagementFactoryHelper provides static factory methods to create
* instances of the management interface.
@@ -141,13 +145,17 @@
}
public static PlatformLoggingMXBean getPlatformLoggingMXBean() {
- if (LoggingSupport.isAvailable()) {
+ if (LoggingMXBeanSupport.isAvailable()) {
return PlatformLoggingImpl.instance;
} else {
return null;
}
}
+ public static boolean isPlatformLoggingMXBeanAvailable() {
+ return LoggingMXBeanSupport.isAvailable();
+ }
+
/**
* The logging MXBean object is an instance of
* PlatformLoggingMXBean and java.util.logging.LoggingMXBean
@@ -165,8 +173,44 @@
extends PlatformLoggingMXBean, java.util.logging.LoggingMXBean {
}
+ // This is a trick: if java.util.logging is not present then
+ // attempting to access something that implements
+ // java.util.logging.LoggingMXBean will trigger a CNFE.
+ // So we cannot directly call any static method or access any static field
+ // on PlatformLoggingImpl, as we would risk raising a CNFE.
+ // Instead we use this intermediate LoggingMXBeanSupport class to determine
+ // whether java.util.logging is present, and load the actual LoggingMXBean
+ // implementation.
+ //
+ static final class LoggingMXBeanSupport {
+ final static Object loggingImpl =
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
+ public Object run() {
+ try {
+ // create a LoggingProxyImpl instance when
+ // java.util.logging classes exist
+ Class<?> c = Class.forName("java.util.logging.Logging", true, null);
+ Constructor<?> cons = c.getDeclaredConstructor();
+ cons.setAccessible(true);
+ return cons.newInstance();
+ } catch (ClassNotFoundException cnf) {
+ return null;
+ } catch (NoSuchMethodException | InstantiationException
+ | IllegalAccessException | InvocationTargetException e) {
+ throw new AssertionError(e);
+ }
+ }});
+
+ static boolean isAvailable() {
+ return loggingImpl != null;
+ }
+ }
+
static class PlatformLoggingImpl implements LoggingMXBean
{
+ final static java.util.logging.LoggingMXBean impl =
+ (java.util.logging.LoggingMXBean) LoggingMXBeanSupport.loggingImpl;
final static PlatformLoggingMXBean instance = new PlatformLoggingImpl();
final static String LOGGING_MXBEAN_NAME = "java.util.logging:type=Logging";
@@ -188,22 +232,22 @@
@Override
public java.util.List<String> getLoggerNames() {
- return LoggingSupport.getLoggerNames();
+ return impl.getLoggerNames();
}
@Override
public String getLoggerLevel(String loggerName) {
- return LoggingSupport.getLoggerLevel(loggerName);
+ return impl.getLoggerLevel(loggerName);
}
@Override
public void setLoggerLevel(String loggerName, String levelName) {
- LoggingSupport.setLoggerLevel(loggerName, levelName);
+ impl.setLoggerLevel(loggerName, levelName);
}
@Override
public String getParentLoggerName(String loggerName) {
- return LoggingSupport.getParentLoggerName(loggerName);
+ return impl.getParentLoggerName(loggerName);
}
}
--- a/jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/KeyStore.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/KeyStore.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -310,7 +310,7 @@
if (alias.equals(entry.getAlias()))
{
X509Certificate[] certChain = entry.getCertificateChain();
- return certChain[0];
+ return certChain.length == 0 ? null : certChain[0];
}
}
@@ -840,7 +840,7 @@
// Obtain certificate factory
if (certificateFactory == null) {
- certificateFactory = CertificateFactory.getInstance("X.509");
+ certificateFactory = CertificateFactory.getInstance("X.509", "SUN");
}
// Generate certificate
--- a/jdk/src/jdk.dev/share/classes/jdk/tools/jimage/ExtractedImage.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/jdk.dev/share/classes/jdk/tools/jimage/ExtractedImage.java Wed Jul 05 21:02:29 2017 +0200
@@ -102,7 +102,6 @@
}
chop = dirPath.toString().length() + 1;
this.moduleName = dirPath.getFileName().toString();
- System.out.println("Module name " + this.moduleName);
this.dirPath = dirPath;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,1286 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.security.jarsigner;
+
+import com.sun.jarsigner.ContentSigner;
+import com.sun.jarsigner.ContentSignerParameters;
+import sun.security.tools.PathList;
+import sun.security.tools.jarsigner.TimestampedSigner;
+import sun.security.util.ManifestDigester;
+import sun.security.util.SignatureFileVerifier;
+import sun.security.x509.AlgorithmId;
+
+import java.io.*;
+import java.net.SocketTimeoutException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.*;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.*;
+import java.util.function.BiConsumer;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * An immutable utility class to sign a jar file.
+ * <p>
+ * A caller creates a {@code JarSigner.Builder} object, (optionally) sets
+ * some parameters, and calls {@link JarSigner.Builder#build build} to create
+ * a {@code JarSigner} object. This {@code JarSigner} object can then
+ * be used to sign a jar file.
+ * <p>
+ * Unless otherwise stated, calling a method of {@code JarSigner} or
+ * {@code JarSigner.Builder} with a null argument will throw
+ * a {@link NullPointerException}.
+ * <p>
+ * Example:
+ * <pre>
+ * JarSigner signer = new JarSigner.Builder(key, certPath)
+ * .digestAlgorithm("SHA-1")
+ * .signatureAlgorithm("SHA1withDSA")
+ * .build();
+ * try (ZipFile in = new ZipFile(inputFile);
+ * FileOutputStream out = new FileOutputStream(outputFile)) {
+ * signer.sign(in, out);
+ * }
+ * </pre>
+ *
+ * @since 1.9
+ */
+@jdk.Exported
+public final class JarSigner {
+
+ /**
+ * A mutable builder class that can create an immutable {@code JarSigner}
+ * from various signing-related parameters.
+ *
+ * @since 1.9
+ */
+ @jdk.Exported
+ public static class Builder {
+
+ // Signer materials:
+ final PrivateKey privateKey;
+ final X509Certificate[] certChain;
+
+ // JarSigner options:
+ // Support multiple digestalg internally. Can be null, but not empty
+ String[] digestalg;
+ String sigalg;
+ // Precisely should be one provider for each digestalg, maybe later
+ Provider digestProvider;
+ Provider sigProvider;
+ URI tsaUrl;
+ String signerName;
+ BiConsumer<String,String> handler;
+
+ // Implementation-specific properties:
+ String tSAPolicyID;
+ String tSADigestAlg;
+ boolean signManifest = true;
+ boolean externalSF = true;
+ String altSignerPath;
+ String altSigner;
+
+ /**
+ * Creates a {@code JarSigner.Builder} object with
+ * a {@link KeyStore.PrivateKeyEntry} object.
+ *
+ * @param entry the {@link KeyStore.PrivateKeyEntry} of the signer.
+ */
+ public Builder(KeyStore.PrivateKeyEntry entry) {
+ this.privateKey = entry.getPrivateKey();
+ try {
+ // called internally, no need to clone
+ Certificate[] certs = entry.getCertificateChain();
+ this.certChain = Arrays.copyOf(certs, certs.length,
+ X509Certificate[].class);
+ } catch (ArrayStoreException ase) {
+ // Wrong type, not X509Certificate. Won't document.
+ throw new IllegalArgumentException(
+ "Entry does not contain X509Certificate");
+ }
+ }
+
+ /**
+ * Creates a {@code JarSigner.Builder} object with a private key and
+ * a certification path.
+ *
+ * @param privateKey the private key of the signer.
+ * @param certPath the certification path of the signer.
+ * @throws IllegalArgumentException if {@code certPath} is empty, or
+ * the {@code privateKey} algorithm does not match the algorithm
+ * of the {@code PublicKey} in the end entity certificate
+ * (the first certificate in {@code certPath}).
+ */
+ public Builder(PrivateKey privateKey, CertPath certPath) {
+ List<? extends Certificate> certs = certPath.getCertificates();
+ if (certs.isEmpty()) {
+ throw new IllegalArgumentException("certPath cannot be empty");
+ }
+ if (!privateKey.getAlgorithm().equals
+ (certs.get(0).getPublicKey().getAlgorithm())) {
+ throw new IllegalArgumentException
+ ("private key algorithm does not match " +
+ "algorithm of public key in end entity " +
+ "certificate (the 1st in certPath)");
+ }
+ this.privateKey = privateKey;
+ try {
+ this.certChain = certs.toArray(new X509Certificate[certs.size()]);
+ } catch (ArrayStoreException ase) {
+ // Wrong type, not X509Certificate.
+ throw new IllegalArgumentException(
+ "Entry does not contain X509Certificate");
+ }
+ }
+
+ /**
+ * Sets the digest algorithm. If no digest algorithm is specified,
+ * the default algorithm returned by {@link #getDefaultDigestAlgorithm}
+ * will be used.
+ *
+ * @param algorithm the standard name of the algorithm. See
+ * the {@code MessageDigest} section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#MessageDigest">
+ * Java Cryptography Architecture Standard Algorithm Name
+ * Documentation</a> for information about standard algorithm names.
+ * @return the {@code JarSigner.Builder} itself.
+ * @throws NoSuchAlgorithmException if {@code algorithm} is not available.
+ */
+ public Builder digestAlgorithm(String algorithm) throws NoSuchAlgorithmException {
+ MessageDigest.getInstance(Objects.requireNonNull(algorithm));
+ this.digestalg = new String[]{algorithm};
+ this.digestProvider = null;
+ return this;
+ }
+
+ /**
+ * Sets the digest algorithm from the specified provider.
+ * If no digest algorithm is specified, the default algorithm
+ * returned by {@link #getDefaultDigestAlgorithm} will be used.
+ *
+ * @param algorithm the standard name of the algorithm. See
+ * the {@code MessageDigest} section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#MessageDigest">
+ * Java Cryptography Architecture Standard Algorithm Name
+ * Documentation</a> for information about standard algorithm names.
+ * @param provider the provider.
+ * @return the {@code JarSigner.Builder} itself.
+ * @throws NoSuchAlgorithmException if {@code algorithm} is not
+ * available in the specified provider.
+ */
+ public Builder digestAlgorithm(String algorithm, Provider provider)
+ throws NoSuchAlgorithmException {
+ MessageDigest.getInstance(
+ Objects.requireNonNull(algorithm),
+ Objects.requireNonNull(provider));
+ this.digestalg = new String[]{algorithm};
+ this.digestProvider = provider;
+ return this;
+ }
+
+ /**
+ * Sets the signature algorithm. If no signature algorithm
+ * is specified, the default signature algorithm returned by
+ * {@link #getDefaultSignatureAlgorithm} for the private key
+ * will be used.
+ *
+ * @param algorithm the standard name of the algorithm. See
+ * the {@code Signature} section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature">
+ * Java Cryptography Architecture Standard Algorithm Name
+ * Documentation</a> for information about standard algorithm names.
+ * @return the {@code JarSigner.Builder} itself.
+ * @throws NoSuchAlgorithmException if {@code algorithm} is not available.
+ * @throws IllegalArgumentException if {@code algorithm} is not
+ * compatible with the algorithm of the signer's private key.
+ */
+ public Builder signatureAlgorithm(String algorithm)
+ throws NoSuchAlgorithmException {
+ // Check availability
+ Signature.getInstance(Objects.requireNonNull(algorithm));
+ AlgorithmId.checkKeyAndSigAlgMatch(
+ privateKey.getAlgorithm(), algorithm);
+ this.sigalg = algorithm;
+ this.sigProvider = null;
+ return this;
+ }
+
+ /**
+ * Sets the signature algorithm from the specified provider. If no
+ * signature algorithm is specified, the default signature algorithm
+ * returned by {@link #getDefaultSignatureAlgorithm} for the private
+ * key will be used.
+ *
+ * @param algorithm the standard name of the algorithm. See
+ * the {@code Signature} section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature">
+ * Java Cryptography Architecture Standard Algorithm Name
+ * Documentation</a> for information about standard algorithm names.
+ * @param provider the provider.
+ * @return the {@code JarSigner.Builder} itself.
+ * @throws NoSuchAlgorithmException if {@code algorithm} is not
+ * available in the specified provider.
+ * @throws IllegalArgumentException if {@code algorithm} is not
+ * compatible with the algorithm of the signer's private key.
+ */
+ public Builder signatureAlgorithm(String algorithm, Provider provider)
+ throws NoSuchAlgorithmException {
+ // Check availability
+ Signature.getInstance(
+ Objects.requireNonNull(algorithm),
+ Objects.requireNonNull(provider));
+ AlgorithmId.checkKeyAndSigAlgMatch(
+ privateKey.getAlgorithm(), algorithm);
+ this.sigalg = algorithm;
+ this.sigProvider = provider;
+ return this;
+ }
+
+ /**
+ * Sets the URI of the Time Stamping Authority (TSA).
+ *
+ * @param uri the URI.
+ * @return the {@code JarSigner.Builder} itself.
+ */
+ public Builder tsa(URI uri) {
+ this.tsaUrl = Objects.requireNonNull(uri);
+ return this;
+ }
+
+ /**
+ * Sets the signer name. The name will be used as the base name for
+ * the signature files. All lowercase characters will be converted to
+ * uppercase for signature file names. If a signer name is not
+ * specified, the string "SIGNER" will be used.
+ *
+ * @param name the signer name.
+ * @return the {@code JarSigner.Builder} itself.
+ * @throws IllegalArgumentException if {@code name} is empty or has
+ * a size bigger than 8, or it contains characters not from the
+ * set "a-zA-Z0-9_-".
+ */
+ public Builder signerName(String name) {
+ if (name.isEmpty() || name.length() > 8) {
+ throw new IllegalArgumentException("Name too long");
+ }
+
+ name = name.toUpperCase(Locale.ENGLISH);
+
+ for (int j = 0; j < name.length(); j++) {
+ char c = name.charAt(j);
+ if (!
+ ((c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') ||
+ (c == '-') ||
+ (c == '_'))) {
+ throw new IllegalArgumentException(
+ "Invalid characters in name");
+ }
+ }
+ this.signerName = name;
+ return this;
+ }
+
+ /**
+ * Sets en event handler that will be triggered when a {@link JarEntry}
+ * is to be added, signed, or updated during the signing process.
+ * <p>
+ * The handler can be used to display signing progress. The first
+ * argument of the handler can be "adding", "signing", or "updating",
+ * and the second argument is the name of the {@link JarEntry}
+ * being processed.
+ *
+ * @param handler the event handler.
+ * @return the {@code JarSigner.Builder} itself.
+ */
+ public Builder eventHandler(BiConsumer<String,String> handler) {
+ this.handler = Objects.requireNonNull(handler);
+ return this;
+ }
+
+ /**
+ * Sets an additional implementation-specific property indicated by
+ * the specified key.
+ *
+ * @implNote This implementation supports the following properties:
+ * <ul>
+ * <li>"tsaDigestAlg": algorithm of digest data in the timestamping
+ * request. The default value is the same as the result of
+ * {@link #getDefaultDigestAlgorithm}.
+ * <li>"tsaPolicyId": TSAPolicyID for Timestamping Authority.
+ * No default value.
+ * <li>"internalsf": "true" if the .SF file is included inside the
+ * signature block, "false" otherwise. Default "false".
+ * <li>"sectionsonly": "true" if the .SF file only contains the hash
+ * value for each section of the manifest and not for the whole
+ * manifest, "false" otherwise. Default "false".
+ * </ul>
+ * All property names are case-insensitive.
+ *
+ * @param key the name of the property.
+ * @param value the value of the property.
+ * @return the {@code JarSigner.Builder} itself.
+ * @throws UnsupportedOperationException if the key is not supported
+ * by this implementation.
+ * @throws IllegalArgumentException if the value is not accepted as
+ * a legal value for this key.
+ */
+ public Builder setProperty(String key, String value) {
+ Objects.requireNonNull(key);
+ Objects.requireNonNull(value);
+ switch (key.toLowerCase(Locale.US)) {
+ case "tsadigestalg":
+ try {
+ MessageDigest.getInstance(value);
+ } catch (NoSuchAlgorithmException nsae) {
+ throw new IllegalArgumentException(
+ "Invalid tsadigestalg", nsae);
+ }
+ this.tSADigestAlg = value;
+ break;
+ case "tsapolicyid":
+ this.tSAPolicyID = value;
+ break;
+ case "internalsf":
+ switch (value) {
+ case "true":
+ externalSF = false;
+ break;
+ case "false":
+ externalSF = true;
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Invalid internalsf value");
+ }
+ break;
+ case "sectionsonly":
+ switch (value) {
+ case "true":
+ signManifest = false;
+ break;
+ case "false":
+ signManifest = true;
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Invalid signManifest value");
+ }
+ break;
+ case "altsignerpath":
+ altSignerPath = value;
+ break;
+ case "altsigner":
+ altSigner = value;
+ break;
+ default:
+ throw new UnsupportedOperationException(
+ "Unsupported key " + key);
+ }
+ return this;
+ }
+
+ /**
+ * Gets the default digest algorithm.
+ *
+ * @implNote This implementation returns "SHA-256". The value may
+ * change in the future.
+ *
+ * @return the default digest algorithm.
+ */
+ public static String getDefaultDigestAlgorithm() {
+ return "SHA-256";
+ }
+
+ /**
+ * Gets the default signature algorithm for a private key.
+ * For example, SHA256withRSA for a 2048-bit RSA key, and
+ * SHA384withECDSA for a 384-bit EC key.
+ *
+ * @implNote This implementation makes use of comparable strengths
+ * as defined in Tables 2 and 3 of NIST SP 800-57 Part 1-Rev.3.
+ * Specifically, if a DSA or RSA key with a key size greater than 7680
+ * bits, or an EC key with a key size greater than or equal to 512 bits,
+ * SHA-512 will be used as the hash function for the signature.
+ * If a DSA or RSA key has a key size greater than 3072 bits, or an
+ * EC key has a key size greater than or equal to 384 bits, SHA-384 will
+ * be used. Otherwise, SHA-256 will be used. The value may
+ * change in the future.
+ *
+ * @param key the private key.
+ * @return the default signature algorithm. Returns null if a default
+ * signature algorithm cannot be found. In this case,
+ * {@link #signatureAlgorithm} must be called to specify a
+ * signature algorithm. Otherwise, the {@link #build} method
+ * will throw an {@link IllegalArgumentException}.
+ */
+ public static String getDefaultSignatureAlgorithm(PrivateKey key) {
+ return AlgorithmId.getDefaultSigAlgForKey(Objects.requireNonNull(key));
+ }
+
+ /**
+ * Builds a {@code JarSigner} object from the parameters set by the
+ * setter methods.
+ * <p>
+ * This method does not modify internal state of this {@code Builder}
+ * object and can be called multiple times to generate multiple
+ * {@code JarSigner} objects. After this method is called, calling
+ * any method on this {@code Builder} will have no effect on
+ * the newly built {@code JarSigner} object.
+ *
+ * @return the {@code JarSigner} object.
+ * @throws IllegalArgumentException if a signature algorithm is not
+ * set and cannot be derived from the private key using the
+ * {@link #getDefaultSignatureAlgorithm} method.
+ */
+ public JarSigner build() {
+ return new JarSigner(this);
+ }
+ }
+
+ private static final String META_INF = "META-INF/";
+
+ // All fields in Builder are duplicated here as final. Those not
+ // provided but has a default value will be filled with default value.
+
+ // Precisely, a final array field can still be modified if only
+ // reference is copied, no clone is done because we are concerned about
+ // casual change instead of malicious attack.
+
+ // Signer materials:
+ private final PrivateKey privateKey;
+ private final X509Certificate[] certChain;
+
+ // JarSigner options:
+ private final String[] digestalg;
+ private final String sigalg;
+ private final Provider digestProvider;
+ private final Provider sigProvider;
+ private final URI tsaUrl;
+ private final String signerName;
+ private final BiConsumer<String,String> handler;
+
+ // Implementation-specific properties:
+ private final String tSAPolicyID;
+ private final String tSADigestAlg;
+ private final boolean signManifest; // "sign" the whole manifest
+ private final boolean externalSF; // leave the .SF out of the PKCS7 block
+ private final String altSignerPath;
+ private final String altSigner;
+
+ private JarSigner(JarSigner.Builder builder) {
+
+ this.privateKey = builder.privateKey;
+ this.certChain = builder.certChain;
+ if (builder.digestalg != null) {
+ // No need to clone because builder only accepts one alg now
+ this.digestalg = builder.digestalg;
+ } else {
+ this.digestalg = new String[] {
+ Builder.getDefaultDigestAlgorithm() };
+ }
+ this.digestProvider = builder.digestProvider;
+ if (builder.sigalg != null) {
+ this.sigalg = builder.sigalg;
+ } else {
+ this.sigalg = JarSigner.Builder
+ .getDefaultSignatureAlgorithm(privateKey);
+ if (this.sigalg == null) {
+ throw new IllegalArgumentException(
+ "No signature alg for " + privateKey.getAlgorithm());
+ }
+ }
+ this.sigProvider = builder.sigProvider;
+ this.tsaUrl = builder.tsaUrl;
+
+ if (builder.signerName == null) {
+ this.signerName = "SIGNER";
+ } else {
+ this.signerName = builder.signerName;
+ }
+ this.handler = builder.handler;
+
+ if (builder.tSADigestAlg != null) {
+ this.tSADigestAlg = builder.tSADigestAlg;
+ } else {
+ this.tSADigestAlg = Builder.getDefaultDigestAlgorithm();
+ }
+ this.tSAPolicyID = builder.tSAPolicyID;
+ this.signManifest = builder.signManifest;
+ this.externalSF = builder.externalSF;
+ this.altSigner = builder.altSigner;
+ this.altSignerPath = builder.altSignerPath;
+ }
+
+ /**
+ * Signs a file into an {@link OutputStream}. This method will not close
+ * {@code file} or {@code os}.
+ *
+ * @param file the file to sign.
+ * @param os the output stream.
+ * @throws JarSignerException if the signing fails.
+ */
+ public void sign(ZipFile file, OutputStream os) {
+ try {
+ sign0(Objects.requireNonNull(file),
+ Objects.requireNonNull(os));
+ } catch (SocketTimeoutException | CertificateException e) {
+ // CertificateException is thrown when the received cert from TSA
+ // has no id-kp-timeStamping in its Extended Key Usages extension.
+ throw new JarSignerException("Error applying timestamp", e);
+ } catch (IOException ioe) {
+ throw new JarSignerException("I/O error", ioe);
+ } catch (NoSuchAlgorithmException | InvalidKeyException e) {
+ throw new JarSignerException("Error in signer materials", e);
+ } catch (SignatureException se) {
+ throw new JarSignerException("Error creating signature", se);
+ }
+ }
+
+ /**
+ * Returns the digest algorithm for this {@code JarSigner}.
+ * <p>
+ * The return value is never null.
+ *
+ * @return the digest algorithm.
+ */
+ public String getDigestAlgorithm() {
+ return digestalg[0];
+ }
+
+ /**
+ * Returns the signature algorithm for this {@code JarSigner}.
+ * <p>
+ * The return value is never null.
+ *
+ * @return the signature algorithm.
+ */
+ public String getSignatureAlgorithm() {
+ return sigalg;
+ }
+
+ /**
+ * Returns the URI of the Time Stamping Authority (TSA).
+ *
+ * @return the URI of the TSA.
+ */
+ public URI getTsa() {
+ return tsaUrl;
+ }
+
+ /**
+ * Returns the signer name of this {@code JarSigner}.
+ * <p>
+ * The return value is never null.
+ *
+ * @return the signer name.
+ */
+ public String getSignerName() {
+ return signerName;
+ }
+
+ /**
+ * Returns the value of an additional implementation-specific property
+ * indicated by the specified key. If a property is not set but has a
+ * default value, the default value will be returned.
+ *
+ * @implNote See {@link JarSigner.Builder#setProperty} for a list of
+ * properties this implementation supports. All property names are
+ * case-insensitive.
+ *
+ * @param key the name of the property.
+ * @return the value for the property.
+ * @throws UnsupportedOperationException if the key is not supported
+ * by this implementation.
+ */
+ public String getProperty(String key) {
+ Objects.requireNonNull(key);
+ switch (key.toLowerCase(Locale.US)) {
+ case "tsadigestalg":
+ return tSADigestAlg;
+ case "tsapolicyid":
+ return tSAPolicyID;
+ case "internalsf":
+ return Boolean.toString(!externalSF);
+ case "sectionsonly":
+ return Boolean.toString(!signManifest);
+ case "altsignerpath":
+ return altSignerPath;
+ case "altsigner":
+ return altSigner;
+ default:
+ throw new UnsupportedOperationException(
+ "Unsupported key " + key);
+ }
+ }
+
+ private void sign0(ZipFile zipFile, OutputStream os)
+ throws IOException, CertificateException, NoSuchAlgorithmException,
+ SignatureException, InvalidKeyException {
+ MessageDigest[] digests;
+ try {
+ digests = new MessageDigest[digestalg.length];
+ for (int i = 0; i < digestalg.length; i++) {
+ if (digestProvider == null) {
+ digests[i] = MessageDigest.getInstance(digestalg[i]);
+ } else {
+ digests[i] = MessageDigest.getInstance(
+ digestalg[i], digestProvider);
+ }
+ }
+ } catch (NoSuchAlgorithmException asae) {
+ // Should not happen. User provided alg were checked, and default
+ // alg should always be available.
+ throw new AssertionError(asae);
+ }
+
+ PrintStream ps = new PrintStream(os);
+ ZipOutputStream zos = new ZipOutputStream(ps);
+
+ Manifest manifest = new Manifest();
+ Map<String, Attributes> mfEntries = manifest.getEntries();
+
+ // The Attributes of manifest before updating
+ Attributes oldAttr = null;
+
+ boolean mfModified = false;
+ boolean mfCreated = false;
+ byte[] mfRawBytes = null;
+
+ // Check if manifest exists
+ ZipEntry mfFile;
+ if ((mfFile = getManifestFile(zipFile)) != null) {
+ // Manifest exists. Read its raw bytes.
+ mfRawBytes = zipFile.getInputStream(mfFile).readAllBytes();
+ manifest.read(new ByteArrayInputStream(mfRawBytes));
+ oldAttr = (Attributes) (manifest.getMainAttributes().clone());
+ } else {
+ // Create new manifest
+ Attributes mattr = manifest.getMainAttributes();
+ mattr.putValue(Attributes.Name.MANIFEST_VERSION.toString(),
+ "1.0");
+ String javaVendor = System.getProperty("java.vendor");
+ String jdkVersion = System.getProperty("java.version");
+ mattr.putValue("Created-By", jdkVersion + " (" + javaVendor
+ + ")");
+ mfFile = new ZipEntry(JarFile.MANIFEST_NAME);
+ mfCreated = true;
+ }
+
+ /*
+ * For each entry in jar
+ * (except for signature-related META-INF entries),
+ * do the following:
+ *
+ * - if entry is not contained in manifest, add it to manifest;
+ * - if entry is contained in manifest, calculate its hash and
+ * compare it with the one in the manifest; if they are
+ * different, replace the hash in the manifest with the newly
+ * generated one. (This may invalidate existing signatures!)
+ */
+ Vector<ZipEntry> mfFiles = new Vector<>();
+
+ boolean wasSigned = false;
+
+ for (Enumeration<? extends ZipEntry> enum_ = zipFile.entries();
+ enum_.hasMoreElements(); ) {
+ ZipEntry ze = enum_.nextElement();
+
+ if (ze.getName().startsWith(META_INF)) {
+ // Store META-INF files in vector, so they can be written
+ // out first
+ mfFiles.addElement(ze);
+
+ if (SignatureFileVerifier.isBlockOrSF(
+ ze.getName().toUpperCase(Locale.ENGLISH))) {
+ wasSigned = true;
+ }
+
+ if (SignatureFileVerifier.isSigningRelated(ze.getName())) {
+ // ignore signature-related and manifest files
+ continue;
+ }
+ }
+
+ if (manifest.getAttributes(ze.getName()) != null) {
+ // jar entry is contained in manifest, check and
+ // possibly update its digest attributes
+ if (updateDigests(ze, zipFile, digests,
+ manifest)) {
+ mfModified = true;
+ }
+ } else if (!ze.isDirectory()) {
+ // Add entry to manifest
+ Attributes attrs = getDigestAttributes(ze, zipFile, digests);
+ mfEntries.put(ze.getName(), attrs);
+ mfModified = true;
+ }
+ }
+
+ // Recalculate the manifest raw bytes if necessary
+ if (mfModified) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ manifest.write(baos);
+ if (wasSigned) {
+ byte[] newBytes = baos.toByteArray();
+ if (mfRawBytes != null
+ && oldAttr.equals(manifest.getMainAttributes())) {
+
+ /*
+ * Note:
+ *
+ * The Attributes object is based on HashMap and can handle
+ * continuation columns. Therefore, even if the contents are
+ * not changed (in a Map view), the bytes that it write()
+ * may be different from the original bytes that it read()
+ * from. Since the signature on the main attributes is based
+ * on raw bytes, we must retain the exact bytes.
+ */
+
+ int newPos = findHeaderEnd(newBytes);
+ int oldPos = findHeaderEnd(mfRawBytes);
+
+ if (newPos == oldPos) {
+ System.arraycopy(mfRawBytes, 0, newBytes, 0, oldPos);
+ } else {
+ // cat oldHead newTail > newBytes
+ byte[] lastBytes = new byte[oldPos +
+ newBytes.length - newPos];
+ System.arraycopy(mfRawBytes, 0, lastBytes, 0, oldPos);
+ System.arraycopy(newBytes, newPos, lastBytes, oldPos,
+ newBytes.length - newPos);
+ newBytes = lastBytes;
+ }
+ }
+ mfRawBytes = newBytes;
+ } else {
+ mfRawBytes = baos.toByteArray();
+ }
+ }
+
+ // Write out the manifest
+ if (mfModified) {
+ // manifest file has new length
+ mfFile = new ZipEntry(JarFile.MANIFEST_NAME);
+ }
+ if (handler != null) {
+ if (mfCreated) {
+ handler.accept("adding", mfFile.getName());
+ } else if (mfModified) {
+ handler.accept("updating", mfFile.getName());
+ }
+ }
+
+ zos.putNextEntry(mfFile);
+ zos.write(mfRawBytes);
+
+ // Calculate SignatureFile (".SF") and SignatureBlockFile
+ ManifestDigester manDig = new ManifestDigester(mfRawBytes);
+ SignatureFile sf = new SignatureFile(digests, manifest, manDig,
+ signerName, signManifest);
+
+ byte[] block;
+
+ Signature signer;
+ if (sigProvider == null ) {
+ signer = Signature.getInstance(sigalg);
+ } else {
+ signer = Signature.getInstance(sigalg, sigProvider);
+ }
+ signer.initSign(privateKey);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ sf.write(baos);
+
+ byte[] content = baos.toByteArray();
+
+ signer.update(content);
+ byte[] signature = signer.sign();
+
+ @SuppressWarnings("deprecation")
+ ContentSigner signingMechanism = null;
+ if (altSigner != null) {
+ signingMechanism = loadSigningMechanism(altSigner,
+ altSignerPath);
+ }
+
+ @SuppressWarnings("deprecation")
+ ContentSignerParameters params =
+ new JarSignerParameters(null, tsaUrl, tSAPolicyID,
+ tSADigestAlg, signature,
+ signer.getAlgorithm(), certChain, content, zipFile);
+ block = sf.generateBlock(params, externalSF, signingMechanism);
+
+ String sfFilename = sf.getMetaName();
+ String bkFilename = sf.getBlockName(privateKey);
+
+ ZipEntry sfFile = new ZipEntry(sfFilename);
+ ZipEntry bkFile = new ZipEntry(bkFilename);
+
+ long time = System.currentTimeMillis();
+ sfFile.setTime(time);
+ bkFile.setTime(time);
+
+ // signature file
+ zos.putNextEntry(sfFile);
+ sf.write(zos);
+
+ if (handler != null) {
+ if (zipFile.getEntry(sfFilename) != null) {
+ handler.accept("updating", sfFilename);
+ } else {
+ handler.accept("adding", sfFilename);
+ }
+ }
+
+ // signature block file
+ zos.putNextEntry(bkFile);
+ zos.write(block);
+
+ if (handler != null) {
+ if (zipFile.getEntry(bkFilename) != null) {
+ handler.accept("updating", bkFilename);
+ } else {
+ handler.accept("adding", bkFilename);
+ }
+ }
+
+ // Write out all other META-INF files that we stored in the
+ // vector
+ for (int i = 0; i < mfFiles.size(); i++) {
+ ZipEntry ze = mfFiles.elementAt(i);
+ if (!ze.getName().equalsIgnoreCase(JarFile.MANIFEST_NAME)
+ && !ze.getName().equalsIgnoreCase(sfFilename)
+ && !ze.getName().equalsIgnoreCase(bkFilename)) {
+ if (handler != null) {
+ if (manifest.getAttributes(ze.getName()) != null) {
+ handler.accept("signing", ze.getName());
+ } else if (!ze.isDirectory()) {
+ handler.accept("adding", ze.getName());
+ }
+ }
+ writeEntry(zipFile, zos, ze);
+ }
+ }
+
+ // Write out all other files
+ for (Enumeration<? extends ZipEntry> enum_ = zipFile.entries();
+ enum_.hasMoreElements(); ) {
+ ZipEntry ze = enum_.nextElement();
+
+ if (!ze.getName().startsWith(META_INF)) {
+ if (handler != null) {
+ if (manifest.getAttributes(ze.getName()) != null) {
+ handler.accept("signing", ze.getName());
+ } else {
+ handler.accept("adding", ze.getName());
+ }
+ }
+ writeEntry(zipFile, zos, ze);
+ }
+ }
+ zipFile.close();
+ zos.close();
+ }
+
+ private void writeEntry(ZipFile zf, ZipOutputStream os, ZipEntry ze)
+ throws IOException {
+ ZipEntry ze2 = new ZipEntry(ze.getName());
+ ze2.setMethod(ze.getMethod());
+ ze2.setTime(ze.getTime());
+ ze2.setComment(ze.getComment());
+ ze2.setExtra(ze.getExtra());
+ if (ze.getMethod() == ZipEntry.STORED) {
+ ze2.setSize(ze.getSize());
+ ze2.setCrc(ze.getCrc());
+ }
+ os.putNextEntry(ze2);
+ writeBytes(zf, ze, os);
+ }
+
+ private void writeBytes
+ (ZipFile zf, ZipEntry ze, ZipOutputStream os) throws IOException {
+ try (InputStream is = zf.getInputStream(ze)) {
+ is.transferTo(os);
+ }
+ }
+
+ private boolean updateDigests(ZipEntry ze, ZipFile zf,
+ MessageDigest[] digests,
+ Manifest mf) throws IOException {
+ boolean update = false;
+
+ Attributes attrs = mf.getAttributes(ze.getName());
+ String[] base64Digests = getDigests(ze, zf, digests);
+
+ for (int i = 0; i < digests.length; i++) {
+ // The entry name to be written into attrs
+ String name = null;
+ try {
+ // Find if the digest already exists. An algorithm could have
+ // different names. For example, last time it was SHA, and this
+ // time it's SHA-1.
+ AlgorithmId aid = AlgorithmId.get(digests[i].getAlgorithm());
+ for (Object key : attrs.keySet()) {
+ if (key instanceof Attributes.Name) {
+ String n = key.toString();
+ if (n.toUpperCase(Locale.ENGLISH).endsWith("-DIGEST")) {
+ String tmp = n.substring(0, n.length() - 7);
+ if (AlgorithmId.get(tmp).equals(aid)) {
+ name = n;
+ break;
+ }
+ }
+ }
+ }
+ } catch (NoSuchAlgorithmException nsae) {
+ // Ignored. Writing new digest entry.
+ }
+
+ if (name == null) {
+ name = digests[i].getAlgorithm() + "-Digest";
+ attrs.putValue(name, base64Digests[i]);
+ update = true;
+ } else {
+ // compare digests, and replace the one in the manifest
+ // if they are different
+ String mfDigest = attrs.getValue(name);
+ if (!mfDigest.equalsIgnoreCase(base64Digests[i])) {
+ attrs.putValue(name, base64Digests[i]);
+ update = true;
+ }
+ }
+ }
+ return update;
+ }
+
+ private Attributes getDigestAttributes(
+ ZipEntry ze, ZipFile zf, MessageDigest[] digests)
+ throws IOException {
+
+ String[] base64Digests = getDigests(ze, zf, digests);
+ Attributes attrs = new Attributes();
+
+ for (int i = 0; i < digests.length; i++) {
+ attrs.putValue(digests[i].getAlgorithm() + "-Digest",
+ base64Digests[i]);
+ }
+ return attrs;
+ }
+
+ /*
+ * Returns manifest entry from given jar file, or null if given jar file
+ * does not have a manifest entry.
+ */
+ private ZipEntry getManifestFile(ZipFile zf) {
+ ZipEntry ze = zf.getEntry(JarFile.MANIFEST_NAME);
+ if (ze == null) {
+ // Check all entries for matching name
+ Enumeration<? extends ZipEntry> enum_ = zf.entries();
+ while (enum_.hasMoreElements() && ze == null) {
+ ze = enum_.nextElement();
+ if (!JarFile.MANIFEST_NAME.equalsIgnoreCase
+ (ze.getName())) {
+ ze = null;
+ }
+ }
+ }
+ return ze;
+ }
+
+ private String[] getDigests(
+ ZipEntry ze, ZipFile zf, MessageDigest[] digests)
+ throws IOException {
+
+ int n, i;
+ try (InputStream is = zf.getInputStream(ze)) {
+ long left = ze.getSize();
+ byte[] buffer = new byte[8192];
+ while ((left > 0)
+ && (n = is.read(buffer, 0, buffer.length)) != -1) {
+ for (i = 0; i < digests.length; i++) {
+ digests[i].update(buffer, 0, n);
+ }
+ left -= n;
+ }
+ }
+
+ // complete the digests
+ String[] base64Digests = new String[digests.length];
+ for (i = 0; i < digests.length; i++) {
+ base64Digests[i] = Base64.getEncoder()
+ .encodeToString(digests[i].digest());
+ }
+ return base64Digests;
+ }
+
+ @SuppressWarnings("fallthrough")
+ private int findHeaderEnd(byte[] bs) {
+ // Initial state true to deal with empty header
+ boolean newline = true; // just met a newline
+ int len = bs.length;
+ for (int i = 0; i < len; i++) {
+ switch (bs[i]) {
+ case '\r':
+ if (i < len - 1 && bs[i + 1] == '\n') i++;
+ // fallthrough
+ case '\n':
+ if (newline) return i + 1; //+1 to get length
+ newline = true;
+ break;
+ default:
+ newline = false;
+ }
+ }
+ // If header end is not found, it means the MANIFEST.MF has only
+ // the main attributes section and it does not end with 2 newlines.
+ // Returns the whole length so that it can be completely replaced.
+ return len;
+ }
+
+ /*
+ * Try to load the specified signing mechanism.
+ * The URL class loader is used.
+ */
+ @SuppressWarnings("deprecation")
+ private ContentSigner loadSigningMechanism(String signerClassName,
+ String signerClassPath) {
+
+ // construct class loader
+ String cpString; // make sure env.class.path defaults to dot
+
+ // do prepends to get correct ordering
+ cpString = PathList.appendPath(
+ System.getProperty("env.class.path"), null);
+ cpString = PathList.appendPath(
+ System.getProperty("java.class.path"), cpString);
+ cpString = PathList.appendPath(signerClassPath, cpString);
+ URL[] urls = PathList.pathToURLs(cpString);
+ ClassLoader appClassLoader = new URLClassLoader(urls);
+
+ try {
+ // attempt to find signer
+ Class<?> signerClass = appClassLoader.loadClass(signerClassName);
+ Object signer = signerClass.newInstance();
+ return (ContentSigner) signer;
+ } catch (ClassNotFoundException|InstantiationException|
+ IllegalAccessException|ClassCastException e) {
+ throw new IllegalArgumentException(
+ "Invalid altSigner or altSignerPath", e);
+ }
+ }
+
+ static class SignatureFile {
+
+ /**
+ * SignatureFile
+ */
+ Manifest sf;
+
+ /**
+ * .SF base name
+ */
+ String baseName;
+
+ public SignatureFile(MessageDigest digests[],
+ Manifest mf,
+ ManifestDigester md,
+ String baseName,
+ boolean signManifest) {
+
+ this.baseName = baseName;
+
+ String version = System.getProperty("java.version");
+ String javaVendor = System.getProperty("java.vendor");
+
+ sf = new Manifest();
+ Attributes mattr = sf.getMainAttributes();
+
+ mattr.putValue(Attributes.Name.SIGNATURE_VERSION.toString(), "1.0");
+ mattr.putValue("Created-By", version + " (" + javaVendor + ")");
+
+ if (signManifest) {
+ for (MessageDigest digest: digests) {
+ mattr.putValue(digest.getAlgorithm() + "-Digest-Manifest",
+ Base64.getEncoder().encodeToString(
+ md.manifestDigest(digest)));
+ }
+ }
+
+ // create digest of the manifest main attributes
+ ManifestDigester.Entry mde =
+ md.get(ManifestDigester.MF_MAIN_ATTRS, false);
+ if (mde != null) {
+ for (MessageDigest digest: digests) {
+ mattr.putValue(digest.getAlgorithm() +
+ "-Digest-" + ManifestDigester.MF_MAIN_ATTRS,
+ Base64.getEncoder().encodeToString(
+ mde.digest(digest)));
+ }
+ } else {
+ throw new IllegalStateException
+ ("ManifestDigester failed to create " +
+ "Manifest-Main-Attribute entry");
+ }
+
+ // go through the manifest entries and create the digests
+ Map<String, Attributes> entries = sf.getEntries();
+ for (String name: mf.getEntries().keySet()) {
+ mde = md.get(name, false);
+ if (mde != null) {
+ Attributes attr = new Attributes();
+ for (MessageDigest digest: digests) {
+ attr.putValue(digest.getAlgorithm() + "-Digest",
+ Base64.getEncoder().encodeToString(
+ mde.digest(digest)));
+ }
+ entries.put(name, attr);
+ }
+ }
+ }
+
+ // Write .SF file
+ public void write(OutputStream out) throws IOException {
+ sf.write(out);
+ }
+
+ // get .SF file name
+ public String getMetaName() {
+ return "META-INF/" + baseName + ".SF";
+ }
+
+ // get .DSA (or .DSA, .EC) file name
+ public String getBlockName(PrivateKey privateKey) {
+ String keyAlgorithm = privateKey.getAlgorithm();
+ return "META-INF/" + baseName + "." + keyAlgorithm;
+ }
+
+ // Generates the PKCS#7 content of block file
+ @SuppressWarnings("deprecation")
+ public byte[] generateBlock(ContentSignerParameters params,
+ boolean externalSF,
+ ContentSigner signingMechanism)
+ throws NoSuchAlgorithmException,
+ IOException, CertificateException {
+
+ if (signingMechanism == null) {
+ signingMechanism = new TimestampedSigner();
+ }
+ return signingMechanism.generateSignedData(
+ params,
+ externalSF,
+ params.getTimestampingAuthority() != null
+ || params.getTimestampingAuthorityCertificate() != null);
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ class JarSignerParameters implements ContentSignerParameters {
+
+ private String[] args;
+ private URI tsa;
+ private byte[] signature;
+ private String signatureAlgorithm;
+ private X509Certificate[] signerCertificateChain;
+ private byte[] content;
+ private ZipFile source;
+ private String tSAPolicyID;
+ private String tSADigestAlg;
+
+ JarSignerParameters(String[] args, URI tsa,
+ String tSAPolicyID, String tSADigestAlg,
+ byte[] signature, String signatureAlgorithm,
+ X509Certificate[] signerCertificateChain,
+ byte[] content, ZipFile source) {
+
+ Objects.requireNonNull(signature);
+ Objects.requireNonNull(signatureAlgorithm);
+ Objects.requireNonNull(signerCertificateChain);
+
+ this.args = args;
+ this.tsa = tsa;
+ this.tSAPolicyID = tSAPolicyID;
+ this.tSADigestAlg = tSADigestAlg;
+ this.signature = signature;
+ this.signatureAlgorithm = signatureAlgorithm;
+ this.signerCertificateChain = signerCertificateChain;
+ this.content = content;
+ this.source = source;
+ }
+
+ public String[] getCommandLine() {
+ return args;
+ }
+
+ public URI getTimestampingAuthority() {
+ return tsa;
+ }
+
+ public X509Certificate getTimestampingAuthorityCertificate() {
+ // We don't use this param. Always provide tsaURI.
+ return null;
+ }
+
+ public String getTSAPolicyID() {
+ return tSAPolicyID;
+ }
+
+ public String getTSADigestAlg() {
+ return tSADigestAlg;
+ }
+
+ public byte[] getSignature() {
+ return signature;
+ }
+
+ public String getSignatureAlgorithm() {
+ return signatureAlgorithm;
+ }
+
+ public X509Certificate[] getSignerCertificateChain() {
+ return signerCertificateChain;
+ }
+
+ public byte[] getContent() {
+ return content;
+ }
+
+ public ZipFile getSource() {
+ return source;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSignerException.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.security.jarsigner;
+
+/**
+ * This exception is thrown when {@link JarSigner#sign} fails.
+ *
+ * @since 1.9
+ */
+@jdk.Exported
+public class JarSignerException extends RuntimeException {
+
+ private static final long serialVersionUID = -4732217075689309530L;
+
+ /**
+ * Constructs a new {@code JarSignerException} with the specified detail
+ * message and cause.
+ * <p>
+ * Note that the detail message associated with
+ * {@code cause} is <i>not</i> automatically incorporated in
+ * this {@code JarSignerException}'s detail message.
+ *
+ * @param message the detail message (which is saved for later retrieval
+ * by the {@link #getMessage()} method).
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A {@code null} value is permitted,
+ * and indicates that the cause is nonexistent or unknown.)
+ */
+ public JarSignerException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
+
--- a/jdk/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java Wed Jul 05 21:02:29 2017 +0200
@@ -29,22 +29,16 @@
import java.util.*;
import java.util.zip.*;
import java.util.jar.*;
-import java.math.BigInteger;
import java.net.URI;
-import java.net.URISyntaxException;
import java.text.Collator;
import java.text.MessageFormat;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.security.*;
-import java.lang.reflect.Constructor;
-import com.sun.jarsigner.ContentSigner;
-import com.sun.jarsigner.ContentSignerParameters;
import java.net.SocketTimeoutException;
import java.net.URL;
-import java.net.URLClassLoader;
import java.security.cert.CertPath;
import java.security.cert.CertPathValidator;
import java.security.cert.CertificateExpiredException;
@@ -53,11 +47,12 @@
import java.security.cert.PKIXParameters;
import java.security.cert.TrustAnchor;
import java.util.Map.Entry;
+
+import jdk.security.jarsigner.JarSigner;
+import jdk.security.jarsigner.JarSignerException;
import sun.security.tools.KeyStoreUtil;
-import sun.security.tools.PathList;
import sun.security.x509.*;
import sun.security.util.*;
-import java.util.Base64;
/**
@@ -88,10 +83,6 @@
collator.setStrength(Collator.PRIMARY);
}
- private static final String META_INF = "META-INF/";
-
- private static final Class<?>[] PARAM_STRING = { String.class };
-
private static final String NONE = "NONE";
private static final String P11KEYSTORE = "PKCS11";
@@ -133,13 +124,13 @@
char[] keypass; // private key password
String sigfile; // name of .SF file
String sigalg; // name of signature algorithm
- String digestalg = "SHA-256"; // name of digest algorithm
+ String digestalg; // name of digest algorithm
String signedjar; // output filename
String tsaUrl; // location of the Timestamping Authority
String tsaAlias; // alias for the Timestamping Authority's certificate
String altCertChain; // file to read alternative cert chain from
String tSAPolicyID;
- String tSADigestAlg = "SHA-256";
+ String tSADigestAlg;
boolean verify = false; // verify the jar
String verbose = null; // verbose output when signing/verifying
boolean showcerts = false; // show certs when verifying
@@ -149,9 +140,6 @@
boolean strict = false; // treat warnings as error
// read zip entry raw bytes
- private ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
- private byte[] buffer = new byte[8192];
- private ContentSigner signingMechanism = null;
private String altSignerClass = null;
private String altSignerClasspath = null;
private ZipFile zipFile = null;
@@ -216,6 +204,9 @@
if ((keystore != null) || (storepass != null)) {
System.out.println(rb.getString("jarsigner.error.") +
e.getMessage());
+ if (debug) {
+ e.printStackTrace();
+ }
System.exit(1);
}
}
@@ -229,12 +220,7 @@
loadKeyStore(keystore, true);
getAliasInfo(alias);
- // load the alternative signing mechanism
- if (altSignerClass != null) {
- signingMechanism = loadSigningMechanism(altSignerClass,
- altSignerClasspath);
- }
- signJar(jarfile, alias, args);
+ signJar(jarfile, alias);
}
} catch (Exception e) {
System.out.println(rb.getString("jarsigner.error.") + e);
@@ -626,8 +612,7 @@
InputStream is = null;
try {
is = jf.getInputStream(je);
- int n;
- while ((n = is.read(buffer, 0, buffer.length)) != -1) {
+ while (is.read(buffer, 0, buffer.length) != -1) {
// we just read. this will throw a SecurityException
// if a signature/digest check fails.
}
@@ -1035,7 +1020,6 @@
return cacheForInKS.get(signer);
}
- boolean found = false;
int result = 0;
List<? extends Certificate> certs = signer.getSignerCertPath().getCertificates();
for (Certificate c : certs) {
@@ -1058,7 +1042,6 @@
}
if (alias != null) {
storeHash.put(c, "(" + alias + ")");
- found = true;
result |= IN_KEYSTORE;
}
}
@@ -1090,7 +1073,7 @@
return output;
}
- void signJar(String jarName, String alias, String[] args)
+ void signJar(String jarName, String alias)
throws Exception {
boolean aliasUsed = false;
X509Certificate tsaCert = null;
@@ -1110,17 +1093,17 @@
for (int j = 0; j < sigfile.length(); j++) {
char c = sigfile.charAt(j);
if (!
- ((c>= 'A' && c<= 'Z') ||
- (c>= '0' && c<= '9') ||
- (c == '-') ||
- (c == '_'))) {
+ ((c>= 'A' && c<= 'Z') ||
+ (c>= '0' && c<= '9') ||
+ (c == '-') ||
+ (c == '_'))) {
if (aliasUsed) {
// convert illegal characters from the alias to be _'s
c = '_';
} else {
- throw new
- RuntimeException(rb.getString
- ("signature.filename.must.consist.of.the.following.characters.A.Z.0.9.or."));
+ throw new
+ RuntimeException(rb.getString
+ ("signature.filename.must.consist.of.the.following.characters.A.Z.0.9.or."));
}
}
tmpSigFile.append(c);
@@ -1149,275 +1132,88 @@
error(rb.getString("unable.to.create.")+tmpJarName, ioe);
}
- PrintStream ps = new PrintStream(fos);
- ZipOutputStream zos = new ZipOutputStream(ps);
-
- /* First guess at what they might be - we don't xclude RSA ones. */
- String sfFilename = (META_INF + sigfile + ".SF").toUpperCase(Locale.ENGLISH);
- String bkFilename = (META_INF + sigfile + ".DSA").toUpperCase(Locale.ENGLISH);
-
- Manifest manifest = new Manifest();
- Map<String,Attributes> mfEntries = manifest.getEntries();
-
- // The Attributes of manifest before updating
- Attributes oldAttr = null;
-
- boolean mfModified = false;
- boolean mfCreated = false;
- byte[] mfRawBytes = null;
-
- try {
- MessageDigest digests[] = { MessageDigest.getInstance(digestalg) };
+ CertPath cp = CertificateFactory.getInstance("X.509")
+ .generateCertPath(Arrays.asList(certChain));
+ JarSigner.Builder builder = new JarSigner.Builder(privateKey, cp);
- // Check if manifest exists
- ZipEntry mfFile;
- if ((mfFile = getManifestFile(zipFile)) != null) {
- // Manifest exists. Read its raw bytes.
- mfRawBytes = getBytes(zipFile, mfFile);
- manifest.read(new ByteArrayInputStream(mfRawBytes));
- oldAttr = (Attributes)(manifest.getMainAttributes().clone());
- } else {
- // Create new manifest
- Attributes mattr = manifest.getMainAttributes();
- mattr.putValue(Attributes.Name.MANIFEST_VERSION.toString(),
- "1.0");
- String javaVendor = System.getProperty("java.vendor");
- String jdkVersion = System.getProperty("java.version");
- mattr.putValue("Created-By", jdkVersion + " (" +javaVendor
- + ")");
- mfFile = new ZipEntry(JarFile.MANIFEST_NAME);
- mfCreated = true;
- }
+ if (verbose != null) {
+ builder.eventHandler((action, file) -> {
+ System.out.println(rb.getString("." + action + ".") + file);
+ });
+ }
+
+ if (digestalg != null) {
+ builder.digestAlgorithm(digestalg);
+ }
+ if (sigalg != null) {
+ builder.signatureAlgorithm(sigalg);
+ }
- /*
- * For each entry in jar
- * (except for signature-related META-INF entries),
- * do the following:
- *
- * - if entry is not contained in manifest, add it to manifest;
- * - if entry is contained in manifest, calculate its hash and
- * compare it with the one in the manifest; if they are
- * different, replace the hash in the manifest with the newly
- * generated one. (This may invalidate existing signatures!)
- */
- Vector<ZipEntry> mfFiles = new Vector<>();
+ URI tsaURI = null;
- boolean wasSigned = false;
-
- for (Enumeration<? extends ZipEntry> enum_=zipFile.entries();
- enum_.hasMoreElements();) {
- ZipEntry ze = enum_.nextElement();
-
- if (ze.getName().startsWith(META_INF)) {
- // Store META-INF files in vector, so they can be written
- // out first
- mfFiles.addElement(ze);
+ if (tsaUrl != null) {
+ tsaURI = new URI(tsaUrl);
+ } else if (tsaAlias != null) {
+ tsaCert = getTsaCert(tsaAlias);
+ tsaURI = TimestampedSigner.getTimestampingURI(tsaCert);
+ }
- if (SignatureFileVerifier.isBlockOrSF(
- ze.getName().toUpperCase(Locale.ENGLISH))) {
- wasSigned = true;
- }
-
- if (signatureRelated(ze.getName())) {
- // ignore signature-related and manifest files
- continue;
- }
- }
-
- if (manifest.getAttributes(ze.getName()) != null) {
- // jar entry is contained in manifest, check and
- // possibly update its digest attributes
- if (updateDigests(ze, zipFile, digests,
- manifest) == true) {
- mfModified = true;
- }
- } else if (!ze.isDirectory()) {
- // Add entry to manifest
- Attributes attrs = getDigestAttributes(ze, zipFile,
- digests);
- mfEntries.put(ze.getName(), attrs);
- mfModified = true;
+ if (tsaURI != null) {
+ if (verbose != null) {
+ System.out.println(
+ rb.getString("requesting.a.signature.timestamp"));
+ if (tsaUrl != null) {
+ System.out.println(rb.getString("TSA.location.") + tsaUrl);
+ } else if (tsaCert != null) {
+ System.out.println(rb.getString("TSA.certificate.") +
+ printCert("", tsaCert, false, null, false));
}
}
-
- // Recalculate the manifest raw bytes if necessary
- if (mfModified) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- manifest.write(baos);
- if (wasSigned) {
- byte[] newBytes = baos.toByteArray();
- if (mfRawBytes != null
- && oldAttr.equals(manifest.getMainAttributes())) {
-
- /*
- * Note:
- *
- * The Attributes object is based on HashMap and can handle
- * continuation columns. Therefore, even if the contents are
- * not changed (in a Map view), the bytes that it write()
- * may be different from the original bytes that it read()
- * from. Since the signature on the main attributes is based
- * on raw bytes, we must retain the exact bytes.
- */
-
- int newPos = findHeaderEnd(newBytes);
- int oldPos = findHeaderEnd(mfRawBytes);
-
- if (newPos == oldPos) {
- System.arraycopy(mfRawBytes, 0, newBytes, 0, oldPos);
- } else {
- // cat oldHead newTail > newBytes
- byte[] lastBytes = new byte[oldPos +
- newBytes.length - newPos];
- System.arraycopy(mfRawBytes, 0, lastBytes, 0, oldPos);
- System.arraycopy(newBytes, newPos, lastBytes, oldPos,
- newBytes.length - newPos);
- newBytes = lastBytes;
- }
- }
- mfRawBytes = newBytes;
- } else {
- mfRawBytes = baos.toByteArray();
- }
+ builder.tsa(tsaURI);
+ if (tSADigestAlg != null) {
+ builder.setProperty("tsaDigestAlg", tSADigestAlg);
}
- // Write out the manifest
- if (mfModified) {
- // manifest file has new length
- mfFile = new ZipEntry(JarFile.MANIFEST_NAME);
+ if (tSAPolicyID != null) {
+ builder.setProperty("tsaPolicyId", tSAPolicyID);
}
+ } else {
+ noTimestamp = true;
+ }
+
+ if (altSignerClass != null) {
+ builder.setProperty("altSigner", altSignerClass);
if (verbose != null) {
- if (mfCreated) {
- System.out.println(rb.getString(".adding.") +
- mfFile.getName());
- } else if (mfModified) {
- System.out.println(rb.getString(".updating.") +
- mfFile.getName());
- }
+ System.out.println(
+ rb.getString("using.an.alternative.signing.mechanism"));
}
- zos.putNextEntry(mfFile);
- zos.write(mfRawBytes);
+ }
- // Calculate SignatureFile (".SF") and SignatureBlockFile
- ManifestDigester manDig = new ManifestDigester(mfRawBytes);
- SignatureFile sf = new SignatureFile(digests, manifest, manDig,
- sigfile, signManifest);
+ if (altSignerClasspath != null) {
+ builder.setProperty("altSignerPath", altSignerClasspath);
+ }
- if (tsaAlias != null) {
- tsaCert = getTsaCert(tsaAlias);
- }
+ builder.signerName(sigfile);
- if (tsaUrl == null && tsaCert == null) {
- noTimestamp = true;
- }
-
- SignatureFile.Block block = null;
+ builder.setProperty("sectionsOnly", Boolean.toString(!signManifest));
+ builder.setProperty("internalSF", Boolean.toString(!externalSF));
- try {
- block =
- sf.generateBlock(privateKey, sigalg, certChain,
- externalSF, tsaUrl, tsaCert, tSAPolicyID, tSADigestAlg,
- signingMechanism, args, zipFile);
- } catch (SocketTimeoutException e) {
+ try {
+ builder.build().sign(zipFile, fos);
+ } catch (JarSignerException e) {
+ Throwable cause = e.getCause();
+ if (cause != null && cause instanceof SocketTimeoutException) {
// Provide a helpful message when TSA is beyond a firewall
error(rb.getString("unable.to.sign.jar.") +
- rb.getString("no.response.from.the.Timestamping.Authority.") +
- "\n -J-Dhttp.proxyHost=<hostname>" +
- "\n -J-Dhttp.proxyPort=<portnumber>\n" +
- rb.getString("or") +
- "\n -J-Dhttps.proxyHost=<hostname> " +
- "\n -J-Dhttps.proxyPort=<portnumber> ", e);
- }
-
- sfFilename = sf.getMetaName();
- bkFilename = block.getMetaName();
-
- ZipEntry sfFile = new ZipEntry(sfFilename);
- ZipEntry bkFile = new ZipEntry(bkFilename);
-
- long time = System.currentTimeMillis();
- sfFile.setTime(time);
- bkFile.setTime(time);
-
- // signature file
- zos.putNextEntry(sfFile);
- sf.write(zos);
- if (verbose != null) {
- if (zipFile.getEntry(sfFilename) != null) {
- System.out.println(rb.getString(".updating.") +
- sfFilename);
- } else {
- System.out.println(rb.getString(".adding.") +
- sfFilename);
- }
+ rb.getString("no.response.from.the.Timestamping.Authority.") +
+ "\n -J-Dhttp.proxyHost=<hostname>" +
+ "\n -J-Dhttp.proxyPort=<portnumber>\n" +
+ rb.getString("or") +
+ "\n -J-Dhttps.proxyHost=<hostname> " +
+ "\n -J-Dhttps.proxyPort=<portnumber> ", e);
+ } else {
+ error(rb.getString("unable.to.sign.jar.")+e.getCause(), e.getCause());
}
-
- if (verbose != null) {
- if (tsaUrl != null || tsaCert != null) {
- System.out.println(
- rb.getString("requesting.a.signature.timestamp"));
- }
- if (tsaUrl != null) {
- System.out.println(rb.getString("TSA.location.") + tsaUrl);
- }
- if (tsaCert != null) {
- URI tsaURI = TimestampedSigner.getTimestampingURI(tsaCert);
- if (tsaURI != null) {
- System.out.println(rb.getString("TSA.location.") +
- tsaURI);
- }
- System.out.println(rb.getString("TSA.certificate.") +
- printCert("", tsaCert, false, null, false));
- }
- if (signingMechanism != null) {
- System.out.println(
- rb.getString("using.an.alternative.signing.mechanism"));
- }
- }
-
- // signature block file
- zos.putNextEntry(bkFile);
- block.write(zos);
- if (verbose != null) {
- if (zipFile.getEntry(bkFilename) != null) {
- System.out.println(rb.getString(".updating.") +
- bkFilename);
- } else {
- System.out.println(rb.getString(".adding.") +
- bkFilename);
- }
- }
-
- // Write out all other META-INF files that we stored in the
- // vector
- for (int i=0; i<mfFiles.size(); i++) {
- ZipEntry ze = mfFiles.elementAt(i);
- if (!ze.getName().equalsIgnoreCase(JarFile.MANIFEST_NAME)
- && !ze.getName().equalsIgnoreCase(sfFilename)
- && !ze.getName().equalsIgnoreCase(bkFilename)) {
- writeEntry(zipFile, zos, ze);
- }
- }
-
- // Write out all other files
- for (Enumeration<? extends ZipEntry> enum_=zipFile.entries();
- enum_.hasMoreElements();) {
- ZipEntry ze = enum_.nextElement();
-
- if (!ze.getName().startsWith(META_INF)) {
- if (verbose != null) {
- if (manifest.getAttributes(ze.getName()) != null)
- System.out.println(rb.getString(".signing.") +
- ze.getName());
- else
- System.out.println(rb.getString(".adding.") +
- ze.getName());
- }
- writeEntry(zipFile, zos, ze);
- }
- }
- } catch(IOException ioe) {
- error(rb.getString("unable.to.sign.jar.")+ioe, ioe);
} finally {
// close the resouces
if (zipFile != null) {
@@ -1425,8 +1221,8 @@
zipFile = null;
}
- if (zos != null) {
- zos.close();
+ if (fos != null) {
+ fos.close();
}
}
@@ -1527,35 +1323,6 @@
}
/**
- * Find the length of header inside bs. The header is a multiple (>=0)
- * lines of attributes plus an empty line. The empty line is included
- * in the header.
- */
- @SuppressWarnings("fallthrough")
- private int findHeaderEnd(byte[] bs) {
- // Initial state true to deal with empty header
- boolean newline = true; // just met a newline
- int len = bs.length;
- for (int i=0; i<len; i++) {
- switch (bs[i]) {
- case '\r':
- if (i < len - 1 && bs[i+1] == '\n') i++;
- // fallthrough
- case '\n':
- if (newline) return i+1; //+1 to get length
- newline = true;
- break;
- default:
- newline = false;
- }
- }
- // If header end is not found, it means the MANIFEST.MF has only
- // the main attributes section and it does not end with 2 newlines.
- // Returns the whole length so that it can be completely replaced.
- return len;
- }
-
- /**
* signature-related files include:
* . META-INF/MANIFEST.MF
* . META-INF/SIG-*
@@ -1619,45 +1386,6 @@
return result;
}
- private void writeEntry(ZipFile zf, ZipOutputStream os, ZipEntry ze)
- throws IOException
- {
- ZipEntry ze2 = new ZipEntry(ze.getName());
- ze2.setMethod(ze.getMethod());
- ze2.setTime(ze.getTime());
- ze2.setComment(ze.getComment());
- ze2.setExtra(ze.getExtra());
- if (ze.getMethod() == ZipEntry.STORED) {
- ze2.setSize(ze.getSize());
- ze2.setCrc(ze.getCrc());
- }
- os.putNextEntry(ze2);
- writeBytes(zf, ze, os);
- }
-
- /**
- * Writes all the bytes for a given entry to the specified output stream.
- */
- private synchronized void writeBytes
- (ZipFile zf, ZipEntry ze, ZipOutputStream os) throws IOException {
- int n;
-
- InputStream is = null;
- try {
- is = zf.getInputStream(ze);
- long left = ze.getSize();
-
- while((left > 0) && (n = is.read(buffer, 0, buffer.length)) != -1) {
- os.write(buffer, 0, n);
- left -= n;
- }
- } finally {
- if (is != null) {
- is.close();
- }
- }
- }
-
void loadKeyStore(String keyStoreName, boolean prompt) {
if (!nullStream && keyStoreName == null) {
@@ -1958,15 +1686,13 @@
}
}
- void error(String message)
- {
+ void error(String message) {
System.out.println(rb.getString("jarsigner.")+message);
System.exit(1);
}
- void error(String message, Exception e)
- {
+ void error(String message, Throwable e) {
System.out.println(rb.getString("jarsigner.")+message);
if (debug) {
e.printStackTrace();
@@ -1990,8 +1716,7 @@
}
}
- char[] getPass(String prompt)
- {
+ char[] getPass(String prompt) {
System.err.print(prompt);
System.err.flush();
try {
@@ -2008,569 +1733,4 @@
// this shouldn't happen
return null;
}
-
- /*
- * Reads all the bytes for a given zip entry.
- */
- private synchronized byte[] getBytes(ZipFile zf,
- ZipEntry ze) throws IOException {
- int n;
-
- InputStream is = null;
- try {
- is = zf.getInputStream(ze);
- baos.reset();
- long left = ze.getSize();
-
- while((left > 0) && (n = is.read(buffer, 0, buffer.length)) != -1) {
- baos.write(buffer, 0, n);
- left -= n;
- }
- } finally {
- if (is != null) {
- is.close();
- }
- }
-
- return baos.toByteArray();
- }
-
- /*
- * Returns manifest entry from given jar file, or null if given jar file
- * does not have a manifest entry.
- */
- private ZipEntry getManifestFile(ZipFile zf) {
- ZipEntry ze = zf.getEntry(JarFile.MANIFEST_NAME);
- if (ze == null) {
- // Check all entries for matching name
- Enumeration<? extends ZipEntry> enum_ = zf.entries();
- while (enum_.hasMoreElements() && ze == null) {
- ze = enum_.nextElement();
- if (!JarFile.MANIFEST_NAME.equalsIgnoreCase
- (ze.getName())) {
- ze = null;
- }
- }
- }
- return ze;
- }
-
- /*
- * Computes the digests of a zip entry, and returns them as an array
- * of base64-encoded strings.
- */
- private synchronized String[] getDigests(ZipEntry ze, ZipFile zf,
- MessageDigest[] digests)
- throws IOException {
-
- int n, i;
- InputStream is = null;
- try {
- is = zf.getInputStream(ze);
- long left = ze.getSize();
- while((left > 0)
- && (n = is.read(buffer, 0, buffer.length)) != -1) {
- for (i=0; i<digests.length; i++) {
- digests[i].update(buffer, 0, n);
- }
- left -= n;
- }
- } finally {
- if (is != null) {
- is.close();
- }
- }
-
- // complete the digests
- String[] base64Digests = new String[digests.length];
- for (i=0; i<digests.length; i++) {
- base64Digests[i] = Base64.getEncoder().encodeToString(digests[i].digest());
- }
- return base64Digests;
- }
-
- /*
- * Computes the digests of a zip entry, and returns them as a list of
- * attributes
- */
- private Attributes getDigestAttributes(ZipEntry ze, ZipFile zf,
- MessageDigest[] digests)
- throws IOException {
-
- String[] base64Digests = getDigests(ze, zf, digests);
- Attributes attrs = new Attributes();
-
- for (int i=0; i<digests.length; i++) {
- attrs.putValue(digests[i].getAlgorithm()+"-Digest",
- base64Digests[i]);
- }
- return attrs;
- }
-
- /*
- * Updates the digest attributes of a manifest entry, by adding or
- * replacing digest values.
- * A digest value is added if the manifest entry does not contain a digest
- * for that particular algorithm.
- * A digest value is replaced if it is obsolete.
- *
- * Returns true if the manifest entry has been changed, and false
- * otherwise.
- */
- private boolean updateDigests(ZipEntry ze, ZipFile zf,
- MessageDigest[] digests,
- Manifest mf) throws IOException {
- boolean update = false;
-
- Attributes attrs = mf.getAttributes(ze.getName());
- String[] base64Digests = getDigests(ze, zf, digests);
-
- for (int i=0; i<digests.length; i++) {
- // The entry name to be written into attrs
- String name = null;
- try {
- // Find if the digest already exists
- AlgorithmId aid = AlgorithmId.get(digests[i].getAlgorithm());
- for (Object key: attrs.keySet()) {
- if (key instanceof Attributes.Name) {
- String n = ((Attributes.Name)key).toString();
- if (n.toUpperCase(Locale.ENGLISH).endsWith("-DIGEST")) {
- String tmp = n.substring(0, n.length() - 7);
- if (AlgorithmId.get(tmp).equals(aid)) {
- name = n;
- break;
- }
- }
- }
- }
- } catch (NoSuchAlgorithmException nsae) {
- // Ignored. Writing new digest entry.
- }
-
- if (name == null) {
- name = digests[i].getAlgorithm()+"-Digest";
- attrs.putValue(name, base64Digests[i]);
- update=true;
- } else {
- // compare digests, and replace the one in the manifest
- // if they are different
- String mfDigest = attrs.getValue(name);
- if (!mfDigest.equalsIgnoreCase(base64Digests[i])) {
- attrs.putValue(name, base64Digests[i]);
- update=true;
- }
- }
- }
- return update;
- }
-
- /*
- * Try to load the specified signing mechanism.
- * The URL class loader is used.
- */
- private ContentSigner loadSigningMechanism(String signerClassName,
- String signerClassPath) throws Exception {
-
- // construct class loader
- String cpString = null; // make sure env.class.path defaults to dot
-
- // do prepends to get correct ordering
- cpString = PathList.appendPath(System.getProperty("env.class.path"), cpString);
- cpString = PathList.appendPath(System.getProperty("java.class.path"), cpString);
- cpString = PathList.appendPath(signerClassPath, cpString);
- URL[] urls = PathList.pathToURLs(cpString);
- ClassLoader appClassLoader = new URLClassLoader(urls);
-
- // attempt to find signer
- Class<?> signerClass = appClassLoader.loadClass(signerClassName);
-
- // Check that it implements ContentSigner
- Object signer = signerClass.newInstance();
- if (!(signer instanceof ContentSigner)) {
- MessageFormat form = new MessageFormat(
- rb.getString("signerClass.is.not.a.signing.mechanism"));
- Object[] source = {signerClass.getName()};
- throw new IllegalArgumentException(form.format(source));
- }
- return (ContentSigner)signer;
- }
}
-
-class SignatureFile {
-
- /** SignatureFile */
- Manifest sf;
-
- /** .SF base name */
- String baseName;
-
- public SignatureFile(MessageDigest digests[],
- Manifest mf,
- ManifestDigester md,
- String baseName,
- boolean signManifest)
-
- {
- this.baseName = baseName;
-
- String version = System.getProperty("java.version");
- String javaVendor = System.getProperty("java.vendor");
-
- sf = new Manifest();
- Attributes mattr = sf.getMainAttributes();
-
- mattr.putValue(Attributes.Name.SIGNATURE_VERSION.toString(), "1.0");
- mattr.putValue("Created-By", version + " (" + javaVendor + ")");
-
- if (signManifest) {
- // sign the whole manifest
- for (int i=0; i < digests.length; i++) {
- mattr.putValue(digests[i].getAlgorithm()+"-Digest-Manifest",
- Base64.getEncoder().encodeToString(md.manifestDigest(digests[i])));
- }
- }
-
- // create digest of the manifest main attributes
- ManifestDigester.Entry mde =
- md.get(ManifestDigester.MF_MAIN_ATTRS, false);
- if (mde != null) {
- for (int i=0; i < digests.length; i++) {
- mattr.putValue(digests[i].getAlgorithm() +
- "-Digest-" + ManifestDigester.MF_MAIN_ATTRS,
- Base64.getEncoder().encodeToString(mde.digest(digests[i])));
- }
- } else {
- throw new IllegalStateException
- ("ManifestDigester failed to create " +
- "Manifest-Main-Attribute entry");
- }
-
- /* go through the manifest entries and create the digests */
-
- Map<String,Attributes> entries = sf.getEntries();
- Iterator<Map.Entry<String,Attributes>> mit =
- mf.getEntries().entrySet().iterator();
- while(mit.hasNext()) {
- Map.Entry<String,Attributes> e = mit.next();
- String name = e.getKey();
- mde = md.get(name, false);
- if (mde != null) {
- Attributes attr = new Attributes();
- for (int i=0; i < digests.length; i++) {
- attr.putValue(digests[i].getAlgorithm()+"-Digest",
- Base64.getEncoder().encodeToString(mde.digest(digests[i])));
- }
- entries.put(name, attr);
- }
- }
- }
-
- /**
- * Writes the SignatureFile to the specified OutputStream.
- *
- * @param out the output stream
- * @exception IOException if an I/O error has occurred
- */
-
- public void write(OutputStream out) throws IOException
- {
- sf.write(out);
- }
-
- /**
- * get .SF file name
- */
- public String getMetaName()
- {
- return "META-INF/"+ baseName + ".SF";
- }
-
- /**
- * get base file name
- */
- public String getBaseName()
- {
- return baseName;
- }
-
- /*
- * Generate a signed data block.
- * If a URL or a certificate (containing a URL) for a Timestamping
- * Authority is supplied then a signature timestamp is generated and
- * inserted into the signed data block.
- *
- * @param sigalg signature algorithm to use, or null to use default
- * @param tsaUrl The location of the Timestamping Authority. If null
- * then no timestamp is requested.
- * @param tsaCert The certificate for the Timestamping Authority. If null
- * then no timestamp is requested.
- * @param signingMechanism The signing mechanism to use.
- * @param args The command-line arguments to jarsigner.
- * @param zipFile The original source Zip file.
- */
- @SuppressWarnings("deprecation")
- public Block generateBlock(PrivateKey privateKey,
- String sigalg,
- X509Certificate[] certChain,
- boolean externalSF, String tsaUrl,
- X509Certificate tsaCert,
- String tSAPolicyID,
- String tSADigestAlg,
- ContentSigner signingMechanism,
- String[] args, ZipFile zipFile)
- throws NoSuchAlgorithmException, InvalidKeyException, IOException,
- SignatureException, CertificateException
- {
- return new Block(this, privateKey, sigalg, certChain, externalSF,
- tsaUrl, tsaCert, tSAPolicyID, tSADigestAlg, signingMechanism, args, zipFile);
- }
-
-
- public static class Block {
-
- private byte[] block;
- private String blockFileName;
-
- /*
- * Construct a new signature block.
- */
- @SuppressWarnings("deprecation")
- Block(SignatureFile sfg, PrivateKey privateKey, String sigalg,
- X509Certificate[] certChain, boolean externalSF, String tsaUrl,
- X509Certificate tsaCert, String tSAPolicyID, String tSADigestAlg,
- ContentSigner signingMechanism, String[] args, ZipFile zipFile)
- throws NoSuchAlgorithmException, InvalidKeyException, IOException,
- SignatureException, CertificateException {
-
- Principal issuerName = certChain[0].getIssuerDN();
- if (!(issuerName instanceof X500Name)) {
- // must extract the original encoded form of DN for subsequent
- // name comparison checks (converting to a String and back to
- // an encoded DN could cause the types of String attribute
- // values to be changed)
- X509CertInfo tbsCert = new
- X509CertInfo(certChain[0].getTBSCertificate());
- issuerName = (Principal)
- tbsCert.get(X509CertInfo.ISSUER + "." +
- X509CertInfo.DN_NAME);
- }
- BigInteger serial = certChain[0].getSerialNumber();
-
- String signatureAlgorithm;
- String keyAlgorithm = privateKey.getAlgorithm();
- /*
- * If no signature algorithm was specified, we choose a
- * default that is compatible with the private key algorithm.
- */
- if (sigalg == null) {
-
- if (keyAlgorithm.equalsIgnoreCase("DSA"))
- signatureAlgorithm = "SHA256withDSA";
- else if (keyAlgorithm.equalsIgnoreCase("RSA"))
- signatureAlgorithm = "SHA256withRSA";
- else if (keyAlgorithm.equalsIgnoreCase("EC"))
- signatureAlgorithm = "SHA256withECDSA";
- else
- throw new RuntimeException("private key is not a DSA or "
- + "RSA key");
- } else {
- signatureAlgorithm = sigalg;
- }
-
- // check common invalid key/signature algorithm combinations
- String sigAlgUpperCase = signatureAlgorithm.toUpperCase(Locale.ENGLISH);
- if ((sigAlgUpperCase.endsWith("WITHRSA") &&
- !keyAlgorithm.equalsIgnoreCase("RSA")) ||
- (sigAlgUpperCase.endsWith("WITHECDSA") &&
- !keyAlgorithm.equalsIgnoreCase("EC")) ||
- (sigAlgUpperCase.endsWith("WITHDSA") &&
- !keyAlgorithm.equalsIgnoreCase("DSA"))) {
- throw new SignatureException
- ("private key algorithm is not compatible with signature algorithm");
- }
-
- blockFileName = "META-INF/"+sfg.getBaseName()+"."+keyAlgorithm;
-
- AlgorithmId sigAlg = AlgorithmId.get(signatureAlgorithm);
- AlgorithmId digEncrAlg = AlgorithmId.get(keyAlgorithm);
-
- Signature sig = Signature.getInstance(signatureAlgorithm);
- sig.initSign(privateKey);
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- sfg.write(baos);
-
- byte[] content = baos.toByteArray();
-
- sig.update(content);
- byte[] signature = sig.sign();
-
- // Timestamp the signature and generate the signature block file
- if (signingMechanism == null) {
- signingMechanism = new TimestampedSigner();
- }
- URI tsaUri = null;
- try {
- if (tsaUrl != null) {
- tsaUri = new URI(tsaUrl);
- }
- } catch (URISyntaxException e) {
- throw new IOException(e);
- }
-
- // Assemble parameters for the signing mechanism
- ContentSignerParameters params =
- new JarSignerParameters(args, tsaUri, tsaCert, tSAPolicyID,
- tSADigestAlg, signature,
- signatureAlgorithm, certChain, content, zipFile);
-
- // Generate the signature block
- block = signingMechanism.generateSignedData(
- params, externalSF, (tsaUrl != null || tsaCert != null));
- }
-
- /*
- * get block file name.
- */
- public String getMetaName()
- {
- return blockFileName;
- }
-
- /**
- * Writes the block file to the specified OutputStream.
- *
- * @param out the output stream
- * @exception IOException if an I/O error has occurred
- */
-
- public void write(OutputStream out) throws IOException
- {
- out.write(block);
- }
- }
-}
-
-
-/*
- * This object encapsulates the parameters used to perform content signing.
- */
-@SuppressWarnings("deprecation")
-class JarSignerParameters implements ContentSignerParameters {
-
- private String[] args;
- private URI tsa;
- private X509Certificate tsaCertificate;
- private byte[] signature;
- private String signatureAlgorithm;
- private X509Certificate[] signerCertificateChain;
- private byte[] content;
- private ZipFile source;
- private String tSAPolicyID;
- private String tSADigestAlg;
-
- /**
- * Create a new object.
- */
- JarSignerParameters(String[] args, URI tsa, X509Certificate tsaCertificate,
- String tSAPolicyID, String tSADigestAlg,
- byte[] signature, String signatureAlgorithm,
- X509Certificate[] signerCertificateChain, byte[] content,
- ZipFile source) {
-
- if (signature == null || signatureAlgorithm == null ||
- signerCertificateChain == null || tSADigestAlg == null) {
- throw new NullPointerException();
- }
- this.args = args;
- this.tsa = tsa;
- this.tsaCertificate = tsaCertificate;
- this.tSAPolicyID = tSAPolicyID;
- this.tSADigestAlg = tSADigestAlg;
- this.signature = signature;
- this.signatureAlgorithm = signatureAlgorithm;
- this.signerCertificateChain = signerCertificateChain;
- this.content = content;
- this.source = source;
- }
-
- /**
- * Retrieves the command-line arguments.
- *
- * @return The command-line arguments. May be null.
- */
- public String[] getCommandLine() {
- return args;
- }
-
- /**
- * Retrieves the identifier for a Timestamping Authority (TSA).
- *
- * @return The TSA identifier. May be null.
- */
- public URI getTimestampingAuthority() {
- return tsa;
- }
-
- /**
- * Retrieves the certificate for a Timestamping Authority (TSA).
- *
- * @return The TSA certificate. May be null.
- */
- public X509Certificate getTimestampingAuthorityCertificate() {
- return tsaCertificate;
- }
-
- public String getTSAPolicyID() {
- return tSAPolicyID;
- }
-
- public String getTSADigestAlg() {
- return tSADigestAlg;
- }
-
- /**
- * Retrieves the signature.
- *
- * @return The non-null signature bytes.
- */
- public byte[] getSignature() {
- return signature;
- }
-
- /**
- * Retrieves the name of the signature algorithm.
- *
- * @return The non-null string name of the signature algorithm.
- */
- public String getSignatureAlgorithm() {
- return signatureAlgorithm;
- }
-
- /**
- * Retrieves the signer's X.509 certificate chain.
- *
- * @return The non-null array of X.509 public-key certificates.
- */
- public X509Certificate[] getSignerCertificateChain() {
- return signerCertificateChain;
- }
-
- /**
- * Retrieves the content that was signed.
- *
- * @return The content bytes. May be null.
- */
- public byte[] getContent() {
- return content;
- }
-
- /**
- * Retrieves the original source ZIP file before it was signed.
- *
- * @return The original ZIP file. May be null.
- */
- public ZipFile getSource() {
- return source;
- }
-}
--- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/InvokableTypeImpl.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/InvokableTypeImpl.java Wed Jul 05 21:02:29 2017 +0200
@@ -236,6 +236,15 @@
final MethodImpl method,
final ValueImpl[] args,
final int options) {
+ /*
+ * Cache the values of args when TRACE_SENDS is enabled, for later printing.
+ * If not cached, printing causes a remote call while synchronized, and deadlock.
+ */
+ if ((vm.traceFlags & VirtualMachineImpl.TRACE_SENDS) != 0) {
+ for (ValueImpl arg: args) {
+ arg.toString();
+ }
+ }
CommandSender sender = getInvokeMethodSender(thread, method, args, options);
PacketStream stream;
if ((options & ClassType.INVOKE_SINGLE_THREADED) != 0) {
--- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1041,12 +1041,11 @@
}
Type findBootType(String signature) throws ClassNotLoadedException {
- List<ReferenceType> types = allClasses();
+ List<ReferenceType> types = retrieveClassesBySignature(signature);
Iterator<ReferenceType> iter = types.iterator();
while (iter.hasNext()) {
ReferenceType type = iter.next();
- if ((type.classLoader() == null) &&
- (type.signature().equals(signature))) {
+ if (type.classLoader() == null) {
return type;
}
}
--- a/jdk/test/ProblemList.txt Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/ProblemList.txt Wed Jul 05 21:02:29 2017 +0200
@@ -133,9 +133,6 @@
# 8029891
java/lang/ClassLoader/deadlock/GetResource.java generic-all
-# 8131129
-java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java windows-all
-
############################################################################
# jdk_instrument
@@ -237,6 +234,7 @@
sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java generic-all
# 8077138: Some PKCS11 tests fail because NSS library is not initialized
+# 8023434: NSS initialization failed
sun/security/pkcs11/Cipher/ReinitCipher.java windows-all
sun/security/pkcs11/Cipher/TestPKCS5PaddingError.java windows-all
sun/security/pkcs11/Cipher/TestRSACipher.java windows-all
@@ -266,6 +264,7 @@
sun/security/pkcs11/Secmod/Crypto.java windows-all
sun/security/pkcs11/Secmod/GetPrivateKey.java windows-all
sun/security/pkcs11/Secmod/JksSetPrivateKey.java windows-all
+sun/security/pkcs11/Secmod/LoadKeystore.java windows-all
sun/security/pkcs11/SecureRandom/Basic.java windows-all
sun/security/pkcs11/SecureRandom/TestDeserialization.java windows-all
sun/security/pkcs11/Serialize/SerializeProvider.java windows-all
--- a/jdk/test/TEST.ROOT Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/TEST.ROOT Wed Jul 05 21:02:29 2017 +0200
@@ -26,5 +26,9 @@
# Allow querying of sun.arch.data.model in @requires clauses
requires.properties=sun.arch.data.model
-# Tests using jtreg 4.1 b11 features
-requiredVersion=4.1 b11
+# Tests using jtreg 4.1 b12 features
+requiredVersion=4.1 b12
+
+# Path to libraries in the topmost test directory. This is needed so @library
+# does not need ../../ notation to reach them
+external.lib.roots = ../../
--- a/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/DumpHeap.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/DumpHeap.java Wed Jul 05 21:02:29 2017 +0200
@@ -38,7 +38,7 @@
* @bug 6455258
* @summary Sanity test for com.sun.management.HotSpotDiagnosticMXBean.dumpHeap method
* @library /lib/testlibrary
- * @library /../../test/lib/share/classes
+ * @library /test/lib/share/classes
* @build jdk.testlibrary.*
* @build jdk.test.lib.hprof.*
* @build jdk.test.lib.hprof.module.*
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/PrintJob/PrinterException.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * @test
+ * @bug 7161283
+ * @summary Toolkit.getPrintJob throws NPE if no printer available
+ * @run main PrinterException
+ */
+import java.awt.Frame;
+import java.awt.JobAttributes;
+import java.awt.PrintJob;
+import java.awt.Toolkit;
+
+public class PrinterException {
+ public static void main(String[] args) {
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ PrintJob pj = null;
+
+ int[][] pageRange = new int[][]{new int[]{1,1}};
+ JobAttributes ja = new JobAttributes(1,
+ java.awt.JobAttributes.DefaultSelectionType.ALL,
+ JobAttributes.DestinationType.FILE, JobAttributes.DialogType.NATIVE,
+ "", Integer.MAX_VALUE, 1,
+ JobAttributes.MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES,
+ pageRange, "", JobAttributes.SidesType.ONE_SIDED);
+ Frame testFrame = new Frame("print");
+ if (tk != null) {
+ pj = tk.getPrintJob(testFrame, null, ja, null);
+ }
+ }
+}
--- a/jdk/test/java/awt/applet/Applet/AppletFlipBuffer.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/awt/applet/Applet/AppletFlipBuffer.java Wed Jul 05 21:02:29 2017 +0200
@@ -21,35 +21,72 @@
* questions.
*/
-/* @test
- @bug 8130390
- @summary Applet fails to launch on virtual desktop
- @author Semyon Sadetsky
- */
+import java.applet.Applet;
+import java.awt.AWTException;
+import java.awt.BufferCapabilities;
+import java.awt.BufferCapabilities.FlipContents;
+import java.awt.Frame;
+import java.awt.ImageCapabilities;
+import java.util.HashSet;
+import java.util.Set;
import sun.awt.AWTAccessor;
+import sun.awt.AWTAccessor.ComponentAccessor;
-import java.applet.Applet;
-import java.awt.*;
+import static java.awt.BufferCapabilities.FlipContents.BACKGROUND;
+import static java.awt.BufferCapabilities.FlipContents.COPIED;
+import static java.awt.BufferCapabilities.FlipContents.PRIOR;
+import static java.awt.BufferCapabilities.FlipContents.UNDEFINED;
+
+/**
+ * @test
+ * @bug 8130390 8134732
+ * @summary Applet fails to launch on virtual desktop
+ * @modules java.desktop/sun.awt
+ * @author Semyon Sadetsky
+ */
+public final class AppletFlipBuffer {
-public class AppletFlipBuffer {
- public static void main(String[] args) throws Exception {
+ static final ImageCapabilities[] ics = {new ImageCapabilities(true),
+ new ImageCapabilities(false)};
+ static final FlipContents[] cntx = {UNDEFINED, BACKGROUND, PRIOR, COPIED};
+ static final Set<BufferCapabilities> bcs = new HashSet<>();
+
+ static {
+ for (final ImageCapabilities icFront : ics) {
+ for (final ImageCapabilities icBack : ics) {
+ for (final FlipContents cnt : cntx) {
+ bcs.add(new BufferCapabilities(icFront, icBack, cnt));
+ }
+ }
+ }
+ }
+
+ public static void main(final String[] args) throws Exception {
Applet applet = new Applet();
- AWTAccessor.ComponentAccessor componentAccessor
- = AWTAccessor.getComponentAccessor();
- BufferCapabilities caps = new BufferCapabilities(
- new ImageCapabilities(true), new ImageCapabilities(true),
- BufferCapabilities.FlipContents.BACKGROUND);
Frame frame = new Frame();
try {
+ frame.setSize(10, 10);
frame.add(applet);
frame.setUndecorated(true);
frame.setVisible(true);
- componentAccessor.createBufferStrategy(applet, 2, caps);
+ test(applet);
System.out.println("ok");
- }
- finally {
+ } finally {
frame.dispose();
}
}
+
+ private static void test(final Applet applet) {
+ ComponentAccessor acc = AWTAccessor.getComponentAccessor();
+ for (int i = 1; i < 10; ++i) {
+ for (final BufferCapabilities caps : bcs) {
+ try {
+ acc.createBufferStrategy(applet, i, caps);
+ } catch (final AWTException ignored) {
+ // this kind of buffer strategy is not supported
+ }
+ }
+ }
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/font/JNICheck/JNICheck.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.swing.*;
+
+public class JNICheck {
+ public static void main(String[] args) throws Exception {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/font/JNICheck/JNICheck.sh Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,61 @@
+#!/bin/ksh -p
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+#
+# @test
+# @bug 6430247 8130507 8020448
+# @summary Tests that there are no JNI warnings.
+# @compile JNICheck.java
+# @run shell/timeout=300 JNICheck.sh
+#
+OS=`uname`
+
+# pick up the compiled class files.
+if [ -z "${TESTCLASSES}" ]; then
+ CP="."
+else
+ CP="${TESTCLASSES}"
+fi
+
+if [ $OS != SunOS -a $OS != Linux ]
+then
+ exit 0
+fi
+
+if [ -z "${TESTJAVA}" ] ; then
+ JAVA_HOME=../../../../../build/solaris-sparc
+else
+ JAVA_HOME=$TESTJAVA
+fi
+
+$JAVA_HOME/bin/java ${TESTVMOPTS} \
+ -cp "${CP}" -Xcheck:jni JNICheck > "${CP}"/log.txt
+
+# any messages logged may indicate a failure.
+if [ -s "${CP}"/log.txt ]; then
+ echo "Test failed"
+ exit 1
+fi
+
+echo "Test passed"
+exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/font/JNICheck/LoadFontsJNICheck.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public class LoadFontsJNICheck {
+ public static void main(String[] args) throws Exception {
+ java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/font/JNICheck/LoadFontsJNICheck.sh Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,62 @@
+#!/bin/sh
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+
+#
+# @test
+# @bug 8138817
+# @summary Tests that there are no JNI warnings about local references.
+# @compile LoadFontsJNICheck.java
+# @run shell/timeout=300 LoadFontsJNICheck.sh
+#
+OS=`uname`
+
+# pick up the compiled class files.
+if [ -z "${TESTCLASSES}" ]; then
+ CP="."
+else
+ CP="${TESTCLASSES}"
+fi
+
+if [ $OS != Darwin ]
+then
+ exit 0
+fi
+
+if [ -z "${TESTJAVA}" ] ; then
+ JAVACMD=java
+else
+ JAVACMD=$TESTJAVA/bin/java
+fi
+
+$JAVACMD ${TESTVMOPTS} \
+ -cp "${CP}" -Xcheck:jni LoadFontsJNICheck | grep "local refs" > "${CP}"/log.txt
+
+# any messages logged may indicate a failure.
+if [ -s "${CP}"/log.txt ]; then
+ echo "Test failed"
+ cat "${CP}"/log.txt
+ exit 1
+fi
+
+echo "Test passed"
+exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/im/8132503/bug8132503.html Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,38 @@
+<!--
+ Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ This code is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License version 2 only, as
+ published by the Free Software Foundation.
+
+ This code is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ version 2 for more details (a copy is included in the LICENSE file that
+ accompanied this code).
+
+ You should have received a copy of the GNU General Public License version
+ 2 along with this work; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ or visit www.oracle.com if you need additional information or have any
+ questions.
+-->
+
+<html>
+<body>
+Verify that Chinese full stop symbol can be entered in JTextArea with Pinyin input method (IM).
+
+This test is for OS X only. For other platforms please simply press "Pass".
+
+1. Go to "System Preferences -> Keyboard -> Input Sources" and add "Pinyin – Traditional" or "Pinyin – Simplified" IM from Chinese language group.
+2. Set current IM to "Pinyin".
+3. Set focus to the text area of the test and press "dot" character on the keyboard.
+4. Set current IM to the IM used before "Pinyin" was set.
+5. If "。" character is displayed in the text area, press "Pass", if "." character is displayed, press "Fail".
+
+<applet code="bug8132503.class" width=400 height=400></applet>
+</body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/im/8132503/bug8132503.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ @bug 8132503
+ @summary [macosx] Chinese full stop symbol cannot be entered with Pinyin IM on OS X
+ @author Anton Litvinov
+ @run applet/manual=yesno bug8132503.html
+ */
+
+import javax.swing.JApplet;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.SwingUtilities;
+
+public class bug8132503 extends JApplet {
+ @Override
+ public void init() {
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ JTextArea textArea = new JTextArea("Text area of the test.", 40, 40);
+ add(new JScrollPane(textArea));
+ }
+ });
+ }
+}
--- a/jdk/test/java/awt/print/PrinterJob/PaintText.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/awt/print/PrinterJob/PaintText.java Wed Jul 05 21:02:29 2017 +0200
@@ -75,8 +75,8 @@
f.show();
/* Non-jtreg execution will display the dialog */
- if (System.getProperty("test.java") == null) {
- if (!pjob.printDialog()) {
+ if (System.getProperty("test.jdk") == null) {
+ if (!pjob.printDialog()) {
return;
}
}
@@ -84,6 +84,8 @@
pjob.print();
} catch (PrinterException e) {
throw new RuntimeException(e.getMessage());
+ } finally {
+ f.dispose();
}
}
--- a/jdk/test/java/beans/XMLDecoder/8028054/Task.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/beans/XMLDecoder/8028054/Task.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,12 +22,17 @@
*/
import java.util.ArrayList;
-import java.util.Enumeration;
import java.util.List;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.net.*;
+import java.io.*;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.FileSystemNotFoundException;
+import java.nio.file.ProviderNotFoundException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.function.Predicate;
abstract class Task<T> implements Runnable {
private transient boolean working = true;
@@ -74,26 +79,74 @@
}
static List<Class<?>> getClasses(int count) throws Exception {
- String resource = ClassLoader.getSystemClassLoader().getResource("java/lang/Object.class").toString();
+ List<Class<?>> classes = new ArrayList<>();
+ FileSystem fs = null;
+
+ try {
+ fs = FileSystems.getFileSystem(URI.create("jrt:/"));
+ } catch (ProviderNotFoundException | FileSystemNotFoundException e) {
+ throw new RuntimeException("FAIL - JRT Filesystem not found");
+ }
+
+ List<String> fileNames;
+ Path modules = fs.getPath("/modules");
- Pattern pattern = Pattern.compile("jar:file:(.*)!.*");
- Matcher matcher = pattern.matcher(resource);
- matcher.matches();
- resource = matcher.group(1);
+ Predicate<String> startsWithJavaBase = path -> path.toString().startsWith("java.base/java");
+ Predicate<String> startsWithJavaDesktop = path -> path.toString().startsWith("java.desktop/java");
+ Predicate<String> startsWithJavaDataTransfer = path -> path.toString().startsWith("java.datatransfer/java");
+ Predicate<String> startsWithJavaRMI = path -> path.toString().startsWith("java.rmi/java");
+ Predicate<String> startsWithJavaSmartCardIO = path -> path.toString().startsWith("java.smartcardio/java");
+ Predicate<String> startsWithJavaManagement = path -> path.toString().startsWith("java.management/java");
+ Predicate<String> startsWithJavaXML = path -> path.toString().startsWith("java.xml/java");
+ Predicate<String> startsWithJavaXMLBind = path -> path.toString().startsWith("java.xml.bind/java");
+ Predicate<String> startsWithJavaScripting = path -> path.toString().startsWith("java.scripting/java");
+ Predicate<String> startsWithJavaNaming = path -> path.toString().startsWith("java.naming/java");
+ Predicate<String> startsWithJavaSQL = path -> path.toString().startsWith("java.sql/java");
+ Predicate<String> startsWithJavaActivation = path -> path.toString().startsWith("java.activation/java");
+ Predicate<String> startsWithJavaCompiler = path -> path.toString().startsWith("java.compiler/java");
+ Predicate<String> startsWithJavaAnnotations = path -> path.toString().startsWith("java.annotations/java");
+ Predicate<String> startsWithJavaTransaction = path -> path.toString().startsWith("java.transaction/java");
+ Predicate<String> startsWithJavaLogging = path -> path.toString().startsWith("java.logging/java");
+ Predicate<String> startsWithJavaCorba = path -> path.toString().startsWith("java.corba/java");
+ Predicate<String> startsWithJavaPrefs = path -> path.toString().startsWith("java.prefs/java");
- List<Class<?>> classes = new ArrayList<>();
- try (JarFile jarFile = new JarFile(resource)) {
- Enumeration<JarEntry> entries = jarFile.entries();
- while (entries.hasMoreElements()) {
- String name = entries.nextElement().getName();
- if (name.startsWith("java") && name.endsWith(".class")) {
- classes.add(Class.forName(name.substring(0, name.indexOf(".")).replace('/', '.')));
- if (count == classes.size()) {
- break;
- }
- }
+ fileNames = Files.walk(modules)
+ .map(Path::toString)
+ .filter(path -> path.toString().contains("java"))
+ .map(s -> s.substring(9)) // remove /modules/ from beginning
+ .filter(startsWithJavaBase
+ .or(startsWithJavaDesktop)
+ .or(startsWithJavaDataTransfer)
+ .or(startsWithJavaRMI)
+ .or(startsWithJavaSmartCardIO)
+ .or(startsWithJavaManagement)
+ .or(startsWithJavaXML)
+ .or(startsWithJavaXMLBind)
+ .or(startsWithJavaScripting)
+ .or(startsWithJavaNaming)
+ .or(startsWithJavaSQL)
+ .or(startsWithJavaActivation)
+ .or(startsWithJavaCompiler)
+ .or(startsWithJavaAnnotations)
+ .or(startsWithJavaTransaction)
+ .or(startsWithJavaLogging)
+ .or(startsWithJavaCorba)
+ .or(startsWithJavaPrefs))
+ .map(s -> s.replace('/', '.'))
+ .filter(path -> path.toString().endsWith(".class"))
+ .map(s -> s.substring(0, s.length() - 6)) // drop .class
+ .map(s -> s.substring(s.indexOf(".")))
+ .filter(path -> path.toString().contains("java"))
+ .map(s -> s.substring(s.indexOf("java")))
+ .collect(Collectors.toList());
+
+ for (String name : fileNames) {
+ classes.add(Class.forName(name));
+ if (count == classes.size()) {
+ break;
}
}
+
return classes;
}
}
--- a/jdk/test/java/beans/XMLDecoder/8028054/TestConstructorFinder.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/beans/XMLDecoder/8028054/TestConstructorFinder.java Wed Jul 05 21:02:29 2017 +0200
@@ -73,8 +73,7 @@
}
Task.print(working + " out of " + alive + " threads are working");
if ((working == 0) && (++alarm == 10)) {
- Task.print("DEADLOCK DETECTED");
- System.exit(100);
+ throw new RuntimeException("FAIL - DEADLOCK DETECTED");
}
Thread.sleep(1000);
}
--- a/jdk/test/java/beans/XMLDecoder/8028054/TestMethodFinder.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/beans/XMLDecoder/8028054/TestMethodFinder.java Wed Jul 05 21:02:29 2017 +0200
@@ -73,8 +73,7 @@
}
Task.print(working + " out of " + alive + " threads are working");
if ((working == 0) && (++alarm == 10)) {
- Task.print("DEADLOCK DETECTED");
- System.exit(100);
+ throw new RuntimeException("FAIL - DEADLOCK DETECTED");
}
Thread.sleep(1000);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ProcessBuilder/PipelineTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Arrays;
+import java.util.List;
+
+/*
+ * @test PipelineTest
+ */
+
+public class PipelineTest {
+
+ private static void realMain(String[] args) throws Throwable {
+ t1_simplePipeline();
+ t2_translatePipeline();
+ t3_redirectErrorStream();
+ t4_failStartPipeline();
+ }
+
+ /**
+ * Return a list of the varargs arguments.
+ * @param args elements to include in the list
+ * @param <T> the type of the elements
+ * @return a {@code List<T>} of the arguments
+ */
+ @SafeVarargs
+ @SuppressWarnings("varargs")
+ static <T> List<T> asList(T... args) {
+ return Arrays.asList(args);
+ }
+
+ /**
+ * T1 - simple copy between two processes
+ */
+ static void t1_simplePipeline() {
+ try {
+ String s1 = "Now is the time to check!";
+ verify(s1, s1,
+ asList(new ProcessBuilder("cat")));
+ verify(s1, s1,
+ asList(new ProcessBuilder("cat"),
+ new ProcessBuilder("cat")));
+ verify(s1, s1,
+ asList(new ProcessBuilder("cat"),
+ new ProcessBuilder("cat"),
+ new ProcessBuilder("cat")));
+ } catch (Throwable t) {
+ unexpected(t);
+ }
+ }
+
+ /**
+ * Pipeline that modifies the content.
+ */
+ static void t2_translatePipeline() {
+ try {
+ String s2 = "Now is the time to check!";
+ String r2 = s2.replace('e', 'E').replace('o', 'O');
+ verify(s2, r2,
+ asList(new ProcessBuilder("tr", "e", "E"),
+ new ProcessBuilder("tr", "o", "O")));
+ } catch (Throwable t) {
+ unexpected(t);
+ }
+ }
+
+ /**
+ * Test that redirectErrorStream sends standard error of the first process
+ * to the standard output. The standard error of the first process should be empty.
+ * The standard output of the 2nd should contain the error message including the bad file name.
+ */
+ static void t3_redirectErrorStream() {
+ try {
+ File p1err = new File("p1-test.err");
+ File p2out = new File("p2-test.out");
+
+ List<Process> processes = ProcessBuilder.startPipeline(
+ asList(new ProcessBuilder("cat", "NON-EXISTENT-FILE")
+ .redirectErrorStream(true)
+ .redirectError(p1err),
+ new ProcessBuilder("cat").redirectOutput(p2out)));
+ waitForAll(processes);
+
+ check("".equals(fileContents(p1err)), "The first process standard error should be empty");
+ String p2contents = fileContents(p2out);
+ check(p2contents.contains("NON-EXISTENT-FILE"),
+ "The error from the first process should be in the output of the second: " + p2contents);
+ } catch (Throwable t) {
+ unexpected(t);
+ }
+ }
+
+ /**
+ * Test that no processes are left after a failed startPipeline.
+ * Test illegal combinations of redirects.
+ */
+ static void t4_failStartPipeline() {
+ File p1err = new File("p1-test.err");
+ File p2out = new File("p2-test.out");
+
+ THROWS(IllegalArgumentException.class,
+ () -> {
+ // Test that output redirect != PIPE throws IAE
+ List<Process> processes = ProcessBuilder.startPipeline(
+ asList(new ProcessBuilder("cat", "NON-EXISTENT-FILE1")
+ .redirectOutput(p1err),
+ new ProcessBuilder("cat")));
+ },
+ () -> {
+ // Test that input redirect != PIPE throws IAE
+ List<Process> processes = ProcessBuilder.startPipeline(
+ asList(new ProcessBuilder("cat", "NON-EXISTENT-FILE2"),
+ new ProcessBuilder("cat").redirectInput(p2out)));
+ }
+ );
+
+ THROWS(NullPointerException.class,
+ () -> {
+ List<Process> processes = ProcessBuilder.startPipeline(
+ asList(new ProcessBuilder("cat", "a"), null));
+ },
+ () -> {
+ List<Process> processes = ProcessBuilder.startPipeline(
+ asList(null, new ProcessBuilder("cat", "b")));
+ }
+ );
+
+ THROWS(IOException.class,
+ () -> {
+ List<Process> processes = ProcessBuilder.startPipeline(
+ asList(new ProcessBuilder("cat", "c"),
+ new ProcessBuilder("NON-EXISTENT-COMMAND")));
+ });
+
+ // Check no subprocess are left behind
+ ProcessHandle.current().children().forEach(PipelineTest::print);
+ ProcessHandle.current().children()
+ .filter(p -> p.info().command().orElse("").contains("cat"))
+ .forEach(p -> fail("process should have been destroyed: " + p));
+ }
+
+ static void verify(String input, String expected, List<ProcessBuilder> builders) throws IOException {
+ File infile = new File("test.in");
+ File outfile = new File("test.out");
+ setFileContents(infile, expected);
+ for (int i = 0; i < builders.size(); i++) {
+ ProcessBuilder b = builders.get(i);
+ if (i == 0) {
+ b.redirectInput(infile);
+ }
+ if (i == builders.size() - 1) {
+ b.redirectOutput(outfile);
+ }
+ }
+ List<Process> processes = ProcessBuilder.startPipeline(builders);
+ verifyProcesses(processes);
+ waitForAll(processes);
+ String result = fileContents(outfile);
+ System.out.printf(" in: %s%nout: %s%n", input, expected);
+ check(result.equals(expected), "result not as expected");
+ }
+
+ /**
+ * Wait for each of the processes to be done.
+ *
+ * @param processes the list of processes to check
+ */
+ static void waitForAll(List<Process> processes) {
+ processes.forEach(p -> {
+ try {
+ int status = p.waitFor();
+ } catch (InterruptedException ie) {
+ unexpected(ie);
+ }
+ });
+ }
+
+ static void print(ProcessBuilder pb) {
+ if (pb != null) {
+ System.out.printf(" pb: %s%n", pb);
+ System.out.printf(" cmd: %s%n", pb.command());
+ }
+ }
+
+ static void print(ProcessHandle p) {
+ System.out.printf("process: pid: %d, info: %s%n",
+ p.getPid(), p.info());
+ }
+
+ // Check various aspects of the processes
+ static void verifyProcesses(List<Process> processes) {
+ for (int i = 0; i < processes.size(); i++) {
+ Process p = processes.get(i);
+ if (i != 0) {
+ verifyNullStream(p.getOutputStream(), "getOutputStream");
+ }
+ if (i == processes.size() - 1) {
+ verifyNullStream(p.getInputStream(), "getInputStream");
+ verifyNullStream(p.getErrorStream(), "getErrorStream");
+ }
+ }
+ }
+
+ static void verifyNullStream(OutputStream s, String msg) {
+ try {
+ s.write(0xff);
+ fail("Stream should have been a NullStream" + msg);
+ } catch (IOException ie) {
+ // expected
+ }
+ }
+
+ static void verifyNullStream(InputStream s, String msg) {
+ try {
+ int len = s.read();
+ check(len == -1, "Stream should have been a NullStream" + msg);
+ } catch (IOException ie) {
+ // expected
+ }
+ }
+
+ static void setFileContents(File file, String contents) {
+ try {
+ Writer w = new FileWriter(file);
+ w.write(contents);
+ w.close();
+ } catch (Throwable t) { unexpected(t); }
+ }
+
+ static String fileContents(File file) {
+ try {
+ Reader r = new FileReader(file);
+ StringBuilder sb = new StringBuilder();
+ char[] buffer = new char[1024];
+ int n;
+ while ((n = r.read(buffer)) != -1)
+ sb.append(buffer,0,n);
+ r.close();
+ return new String(sb);
+ } catch (Throwable t) { unexpected(t); return ""; }
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ static volatile int passed = 0, failed = 0;
+ static void pass() {passed++;}
+ static void fail() {failed++; Thread.dumpStack();}
+ static void fail(String msg) {System.err.println(msg); fail();}
+ static void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ static void check(boolean cond) {if (cond) pass(); else fail();}
+ static void check(boolean cond, String m) {if (cond) pass(); else fail(m);}
+ static void equal(Object x, Object y) {
+ if (x == null ? y == null : x.equals(y)) pass();
+ else fail(">'" + x + "'<" + " not equal to " + "'" + y + "'");
+ }
+
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");
+ }
+ interface Fun {void f() throws Throwable;}
+ static void THROWS(Class<? extends Throwable> k, Fun... fs) {
+ for (Fun f : fs)
+ try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
+ catch (Throwable t) {
+ if (k.isAssignableFrom(t.getClass())) pass();
+ else unexpected(t);}
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/Logger/Level/LoggerLevelTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.System.Logger.Level;
+import java.util.EnumSet;
+import java.util.Objects;
+import java.util.Set;
+/**
+ * @test
+ * @bug 8140364
+ * @summary Tests System.Logger.Level names and severity.
+ * @author danielfuchs
+ */
+public class LoggerLevelTest {
+ public static void main(String[] args) {
+ Set<Level> untested = EnumSet.allOf(Level.class);
+ testLevel(untested, Level.ALL, java.util.logging.Level.ALL);
+ testLevel(untested, Level.TRACE, java.util.logging.Level.FINER);
+ testLevel(untested, Level.DEBUG, java.util.logging.Level.FINE);
+ testLevel(untested, Level.INFO, java.util.logging.Level.INFO);
+ testLevel(untested, Level.WARNING, java.util.logging.Level.WARNING);
+ testLevel(untested, Level.ERROR, java.util.logging.Level.SEVERE);
+ testLevel(untested, Level.OFF, java.util.logging.Level.OFF);
+ if (!untested.isEmpty()) {
+ throw new RuntimeException("Some level values were not tested: " + untested);
+ }
+ }
+
+ private static void testLevel(Set<Level> untested, Level systemLevel, java.util.logging.Level julLevel) {
+ untested.remove(systemLevel);
+ assertEquals(systemLevel.getName(), systemLevel.name(),
+ "System.Logger.Level." + systemLevel.name() + ".getName()");
+ assertEquals(systemLevel.getSeverity(), julLevel.intValue(),
+ "System.Logger.Level." + systemLevel.name() + ".getSeverity");
+ }
+
+ private static void assertEquals(Object actual, Object expected, String what) {
+ if (!Objects.equals(actual, expected)) {
+ throw new RuntimeException("Bad value for " + what
+ + "\n\t expected: " + expected
+ + "\n\t actual: " + actual);
+ } else {
+ System.out.println("Got expected value for " + what + ": " + actual);
+ }
+ }
+
+ private static void assertEquals(int actual, int expected, String what) {
+ if (!Objects.equals(actual, expected)) {
+ throw new RuntimeException("Bad value for " + what
+ + "\n\t expected: " + toString(expected)
+ + "\n\t actual: " + toString(actual));
+ } else {
+ System.out.println("Got expected value for " + what + ": " + toString(actual));
+ }
+ }
+
+ private static String toString(int value) {
+ switch (value) {
+ case Integer.MAX_VALUE: return "Integer.MAX_VALUE";
+ case Integer.MIN_VALUE: return "Integer.MIN_VALUE";
+ default:
+ return Integer.toString(value);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/Logger/custom/AccessSystemLogger.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.IOException;
+import java.lang.System.Logger;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ResourceBundle;
+
+/**
+ *
+ * @author danielfuchs
+ */
+public final class AccessSystemLogger {
+
+ public AccessSystemLogger() {
+ this(check());
+ }
+
+ private AccessSystemLogger(Void unused) {
+ }
+
+ private static Void check() {
+ if (AccessSystemLogger.class.getClassLoader() != null) {
+ throw new RuntimeException("AccessSystemLogger should be loaded by the null classloader");
+ }
+ return null;
+ }
+
+ public Logger getLogger(String name) {
+ Logger logger = System.getLogger(name);
+ System.out.println("System.getLogger(\"" + name + "\"): " + logger);
+ return logger;
+ }
+
+ public Logger getLogger(String name, ResourceBundle bundle) {
+ Logger logger = System.getLogger(name, bundle);
+ System.out.println("System.getLogger(\"" + name + "\", bundle): " + logger);
+ return logger;
+ }
+
+ // copy AccessSystemLogger.class to ./boot
+ public static void main(String[] args) throws IOException {
+ Path testDir = Paths.get(System.getProperty("user.dir", "."));
+ Path bootDir = Paths.get(testDir.toString(), "boot");
+ Path classes = Paths.get(System.getProperty("test.classes", "build/classes"));
+ Path thisClass = Paths.get(classes.toString(),
+ AccessSystemLogger.class.getSimpleName()+".class");
+ if (Files.notExists(bootDir)) {
+ Files.createDirectory(bootDir);
+ }
+ Path dest = Paths.get(bootDir.toString(),
+ AccessSystemLogger.class.getSimpleName()+".class");
+ Files.copy(thisClass, dest, StandardCopyOption.REPLACE_EXISTING);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/Logger/custom/CustomLoggerTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,728 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.ResourceBundle;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Supplier;
+import java.lang.System.LoggerFinder;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.util.stream.Stream;
+
+/**
+ * @test
+ * @bug 8140364
+ * @summary Tests loggers returned by System.getLogger with a naive implementation
+ * of LoggerFinder, and in particular the default body of
+ * System.Logger methods.
+ * @build CustomLoggerTest AccessSystemLogger
+ * @run driver AccessSystemLogger
+ * @run main/othervm -Xbootclasspath/a:boot CustomLoggerTest NOSECURITY
+ * @run main/othervm -Xbootclasspath/a:boot CustomLoggerTest NOPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot CustomLoggerTest WITHPERMISSIONS
+ * @author danielfuchs
+ */
+public class CustomLoggerTest {
+
+ final static AtomicLong sequencer = new AtomicLong();
+ final static boolean VERBOSE = false;
+ static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+
+ public static class MyBundle extends ResourceBundle {
+
+ final ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>();
+
+ @Override
+ protected Object handleGetObject(String key) {
+ if (key.contains(" (translated)")) {
+ throw new RuntimeException("Unexpected key: " + key);
+ }
+ return map.computeIfAbsent(key, k -> k + " (translated)");
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ return Collections.enumeration(map.keySet());
+ }
+
+ }
+ public static class MyLoggerBundle extends MyBundle {
+
+ }
+
+
+ public static class BaseLoggerFinder extends LoggerFinder {
+ final ConcurrentHashMap<String, LoggerImpl> system = new ConcurrentHashMap<>();
+ final ConcurrentHashMap<String, LoggerImpl> user = new ConcurrentHashMap<>();
+ public Queue<LogEvent> eventQueue = new ArrayBlockingQueue<>(128);
+
+ // changing this to true requires changing the logic in the
+ // test in order to load this class with a protection domain
+ // that has the CONTROL_PERMISSION (e.g. by using a custom
+ // system class loader.
+ final boolean doChecks = false;
+
+ public static final class LogEvent {
+
+ public LogEvent() {
+ this(sequencer.getAndIncrement());
+ }
+
+ LogEvent(long sequenceNumber) {
+ this.sequenceNumber = sequenceNumber;
+ }
+
+ long sequenceNumber;
+ boolean isLoggable;
+ String loggerName;
+ Level level;
+ ResourceBundle bundle;
+ Throwable thrown;
+ Object[] args;
+ Supplier<String> supplier;
+ String msg;
+
+ Object[] toArray() {
+ return new Object[] {
+ sequenceNumber,
+ isLoggable,
+ loggerName,
+ level,
+ bundle,
+ thrown,
+ args,
+ supplier,
+ msg,
+ };
+ }
+
+ @Override
+ public String toString() {
+ return Arrays.deepToString(toArray());
+ }
+
+
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof LogEvent
+ && Objects.deepEquals(this.toArray(), ((LogEvent)obj).toArray());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(toArray());
+ }
+
+
+ public static LogEvent of(boolean isLoggable, String name,
+ Level level, ResourceBundle bundle,
+ String key, Throwable thrown) {
+ LogEvent evt = new LogEvent();
+ evt.isLoggable = isLoggable;
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = null;
+ evt.bundle = bundle;
+ evt.thrown = thrown;
+ evt.supplier = null;
+ evt.msg = key;
+ return evt;
+ }
+
+ public static LogEvent of(boolean isLoggable, String name,
+ Level level, ResourceBundle bundle,
+ String key, Object... params) {
+ LogEvent evt = new LogEvent();
+ evt.isLoggable = isLoggable;
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = params;
+ evt.bundle = bundle;
+ evt.thrown = null;
+ evt.supplier = null;
+ evt.msg = key;
+ return evt;
+ }
+
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ Level level, ResourceBundle bundle,
+ String key, Supplier<String> supplier,
+ Throwable thrown, Object... params) {
+ LogEvent evt = new LogEvent(sequenceNumber);
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = params;
+ evt.bundle = bundle;
+ evt.thrown = thrown;
+ evt.supplier = supplier;
+ evt.msg = key;
+ evt.isLoggable = isLoggable;
+ return evt;
+ }
+
+ }
+
+ public class LoggerImpl implements Logger {
+ private final String name;
+ private Level level = Level.INFO;
+
+ public LoggerImpl(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean isLoggable(Level level) {
+ return this.level != Level.OFF && this.level.getSeverity() <= level.getSeverity();
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle, String key, Throwable thrown) {
+ log(LogEvent.of(isLoggable(level), this.name, level, bundle, key, thrown));
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle, String format, Object... params) {
+ log(LogEvent.of(isLoggable(level), name, level, bundle, format, params));
+ }
+
+ void log(LogEvent event) {
+ eventQueue.add(event);
+ }
+ }
+
+ @Override
+ public Logger getLogger(String name, Class<?> caller) {
+ // We should check the permission to obey the API contract, but
+ // what happens if we don't?
+ // This is the main difference compared with what we test in
+ // java/lang/System/LoggerFinder/BaseLoggerFinderTest
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null && doChecks) {
+ sm.checkPermission(SimplePolicy.LOGGERFINDER_PERMISSION);
+ }
+
+ PrivilegedAction<ClassLoader> pa = () -> caller.getClassLoader();
+ ClassLoader callerLoader = AccessController.doPrivileged(pa);
+ if (callerLoader == null) {
+ return system.computeIfAbsent(name, (n) -> new LoggerImpl(n));
+ } else {
+ return user.computeIfAbsent(name, (n) -> new LoggerImpl(n));
+ }
+ }
+ }
+
+ static final AccessSystemLogger accessSystemLogger = new AccessSystemLogger();
+
+ static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS};
+
+ static void setSecurityManager() {
+ if (System.getSecurityManager() == null) {
+ Policy.setPolicy(new SimplePolicy(allowControl));
+ System.setSecurityManager(new SecurityManager());
+ }
+ }
+ public static void main(String[] args) {
+ if (args.length == 0)
+ args = new String[] {
+ "NOSECURITY",
+ "NOPERMISSIONS",
+ "WITHPERMISSIONS"
+ };
+
+ // 1. Obtain destination loggers directly from the LoggerFinder
+ // - LoggerFinder.getLogger("foo", type)
+ BaseLoggerFinder provider =
+ BaseLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
+ BaseLoggerFinder.LoggerImpl appSink =
+ BaseLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", CustomLoggerTest.class));
+ BaseLoggerFinder.LoggerImpl sysSink =
+ BaseLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class));
+
+
+ Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> {
+ switch (testCase) {
+ case NOSECURITY:
+ System.out.println("\n*** Without Security Manager\n");
+ test(provider, true, appSink, sysSink);
+ System.out.println("Tetscase count: " + sequencer.get());
+ break;
+ case NOPERMISSIONS:
+ System.out.println("\n*** With Security Manager, without permissions\n");
+ setSecurityManager();
+ test(provider, false, appSink, sysSink);
+ System.out.println("Tetscase count: " + sequencer.get());
+ break;
+ case WITHPERMISSIONS:
+ System.out.println("\n*** With Security Manager, with control permission\n");
+ setSecurityManager();
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ test(provider, true, appSink, sysSink);
+ } finally {
+ allowControl.get().set(control);
+ }
+ break;
+ default:
+ throw new RuntimeException("Unknown test case: " + testCase);
+ }
+ });
+ System.out.println("\nPASSED: Tested " + sequencer.get() + " cases.");
+ }
+
+ public static void test(BaseLoggerFinder provider, boolean hasRequiredPermissions,
+ BaseLoggerFinder.LoggerImpl appSink, BaseLoggerFinder.LoggerImpl sysSink) {
+
+ ResourceBundle loggerBundle = ResourceBundle.getBundle(MyLoggerBundle.class.getName());
+ final Map<Logger, String> loggerDescMap = new HashMap<>();
+
+
+ // 1. Test loggers returned by:
+ // - System.getLogger("foo")
+ // - and AccessSystemLogger.getLogger("foo")
+ Logger appLogger1 = System.getLogger("foo");
+ loggerDescMap.put(appLogger1, "System.getLogger(\"foo\");");
+
+ Logger sysLogger1 = null;
+ try {
+ sysLogger1 = accessSystemLogger.getLogger("foo");
+ loggerDescMap.put(sysLogger1, "AccessSystemLogger.getLogger(\"foo\")");
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(SimplePolicy.LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ throw new RuntimeException("unexpected exception: " + acx, acx);
+ }
+
+ if (appLogger1 == sysLogger1) {
+ throw new RuntimeException("identical loggers");
+ }
+
+ if (provider.system.contains(appLogger1)) {
+ throw new RuntimeException("app logger in system map");
+ }
+ if (provider.user.contains(sysLogger1)) {
+ throw new RuntimeException("sys logger in appplication map");
+ }
+ if (provider.system.contains(sysLogger1)) {
+ // sysLogger should be a a LazyLoggerWrapper
+ throw new RuntimeException("sys logger is in system map (should be wrapped)");
+ }
+
+
+ // 2. Test loggers returned by:
+ // - System.getLogger(\"foo\", loggerBundle)
+ // - and AccessSystemLogger.getLogger(\"foo\", loggerBundle)
+ Logger appLogger2 =
+ System.getLogger("foo", loggerBundle);
+ loggerDescMap.put(appLogger2, "System.getLogger(\"foo\", loggerBundle)");
+
+ Logger sysLogger2 = null;
+ try {
+ sysLogger2 = accessSystemLogger.getLogger("foo", loggerBundle);
+ loggerDescMap.put(sysLogger2, "AccessSystemLogger.getLogger(\"foo\", loggerBundle)");
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(SimplePolicy.LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ throw new RuntimeException("unexpected exception: " + acx, acx);
+ }
+ if (appLogger2 == sysLogger2) {
+ throw new RuntimeException("identical loggers");
+ }
+ if (appLogger2 == appSink) {
+ throw new RuntimeException("identical loggers");
+ }
+ if (sysLogger2 == sysSink) {
+ throw new RuntimeException("identical loggers");
+ }
+
+ if (provider.system.contains(appLogger2)) {
+ throw new RuntimeException("localized app logger in system map");
+ }
+ if (provider.user.contains(appLogger2)) {
+ throw new RuntimeException("localized app logger in appplication map");
+ }
+ if (provider.user.contains(sysLogger2)) {
+ throw new RuntimeException("localized sys logger in appplication map");
+ }
+ if (provider.system.contains(sysLogger2)) {
+ throw new RuntimeException("localized sys logger not in system map");
+ }
+
+ testLogger(provider, loggerDescMap, "foo", null, appLogger1, appSink);
+ testLogger(provider, loggerDescMap, "foo", null, sysLogger1, sysSink);
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, appLogger2, appSink);
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, sysLogger2, sysSink);
+ }
+
+ public static class Foo {
+
+ }
+
+ static void verbose(String msg) {
+ if (VERBOSE) {
+ System.out.println(msg);
+ }
+ }
+
+ // Calls the 8 methods defined on Logger and verify the
+ // parameters received by the underlying BaseLoggerFinder.LoggerImpl
+ // logger.
+ private static void testLogger(BaseLoggerFinder provider,
+ Map<Logger, String> loggerDescMap,
+ String name,
+ ResourceBundle loggerBundle,
+ Logger logger,
+ BaseLoggerFinder.LoggerImpl sink) {
+
+ System.out.println("Testing " + loggerDescMap.get(logger));
+
+ Foo foo = new Foo();
+ String fooMsg = foo.toString();
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, foo): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ BaseLoggerFinder.LogEvent expected =
+ BaseLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0,
+ name, messageLevel, (ResourceBundle)null,
+ fooMsg, null, (Throwable)null, (Object[])null);
+ logger.log(messageLevel, foo);
+ if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (provider.eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ BaseLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ String msg = "blah";
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, \"blah\"): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ BaseLoggerFinder.LogEvent expected =
+ BaseLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
+ name, messageLevel, loggerBundle,
+ msg, null, (Throwable)null, (Object[])null);
+ logger.log(messageLevel, msg);
+ BaseLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+
+ Supplier<String> fooSupplier = new Supplier<String>() {
+ @Override
+ public String get() {
+ return this.toString();
+ }
+ };
+
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, fooSupplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ BaseLoggerFinder.LogEvent expected =
+ BaseLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0,
+ name, messageLevel, (ResourceBundle)null,
+ fooSupplier.get(), null,
+ (Throwable)null, (Object[])null);
+ logger.log(messageLevel, fooSupplier);
+ if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (provider.eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ BaseLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ String format = "two params [{1} {2}]";
+ Object arg1 = foo;
+ Object arg2 = msg;
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, format, params...): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ BaseLoggerFinder.LogEvent expected =
+ BaseLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
+ name, messageLevel, loggerBundle,
+ format, null, (Throwable)null, new Object[] {arg1, arg2});
+ logger.log(messageLevel, format, arg1, arg2);
+ BaseLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+
+ Throwable thrown = new Exception("OK: log me!");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, \"blah\", thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ BaseLoggerFinder.LogEvent expected =
+ BaseLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
+ name, messageLevel, loggerBundle,
+ msg, null, thrown, (Object[]) null);
+ logger.log(messageLevel, msg, thrown);
+ BaseLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+
+
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, thrown, fooSupplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ BaseLoggerFinder.LogEvent expected =
+ BaseLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0,
+ name, messageLevel, (ResourceBundle)null,
+ fooSupplier.get(), null,
+ (Throwable)thrown, (Object[])null);
+ logger.log(messageLevel, fooSupplier, thrown);
+ if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (provider.eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ BaseLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ ResourceBundle bundle = ResourceBundle.getBundle(MyBundle.class.getName());
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, bundle, format, params...): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ BaseLoggerFinder.LogEvent expected =
+ BaseLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
+ name, messageLevel, bundle,
+ format, null, (Throwable)null, new Object[] {foo, msg});
+ logger.log(messageLevel, bundle, format, foo, msg);
+ BaseLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, bundle, \"blah\", thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ BaseLoggerFinder.LogEvent expected =
+ BaseLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
+ name, messageLevel, bundle,
+ msg, null, thrown, (Object[]) null);
+ logger.log(messageLevel, bundle, msg, thrown);
+ BaseLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ final static class PermissionsBuilder {
+ final Permissions perms;
+ public PermissionsBuilder() {
+ this(new Permissions());
+ }
+ public PermissionsBuilder(Permissions perms) {
+ this.perms = perms;
+ }
+ public PermissionsBuilder add(Permission p) {
+ perms.add(p);
+ return this;
+ }
+ public PermissionsBuilder addAll(PermissionCollection col) {
+ if (col != null) {
+ for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
+ perms.add(e.nextElement());
+ }
+ }
+ return this;
+ }
+ public Permissions toPermissions() {
+ final PermissionsBuilder builder = new PermissionsBuilder();
+ builder.addAll(perms);
+ return builder.perms;
+ }
+ }
+
+ public static class SimplePolicy extends Policy {
+
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+ final Permissions permissions;
+ final Permissions allPermissions;
+ final ThreadLocal<AtomicBoolean> allowControl;
+ public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl) {
+ this.allowControl = allowControl;
+ permissions = new Permissions();
+
+ // these are used for configuring the test itself...
+ allPermissions = new Permissions();
+ allPermissions.add(LOGGERFINDER_PERMISSION);
+
+ }
+
+ @Override
+ public boolean implies(ProtectionDomain domain, Permission permission) {
+ if (allowControl.get().get()) return allPermissions.implies(permission);
+ return permissions.implies(permission);
+ }
+
+ @Override
+ public PermissionCollection getPermissions(CodeSource codesource) {
+ return new PermissionsBuilder().addAll(allowControl.get().get()
+ ? allPermissions : permissions).toPermissions();
+ }
+
+ @Override
+ public PermissionCollection getPermissions(ProtectionDomain domain) {
+ return new PermissionsBuilder().addAll(allowControl.get().get()
+ ? allPermissions : permissions).toPermissions();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/Logger/custom/META-INF/services/java.lang.System$LoggerFinder Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,1 @@
+CustomLoggerTest$BaseLoggerFinder
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/Logger/default/AccessSystemLogger.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.IOException;
+import java.lang.System.Logger;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ResourceBundle;
+import java.util.logging.LogManager;
+
+/**
+ *
+ * @author danielfuchs
+ */
+public final class AccessSystemLogger {
+
+ public AccessSystemLogger() {
+ this(check());
+ }
+
+ private AccessSystemLogger(Void unused) {
+ }
+
+ private static Void check() {
+ if (AccessSystemLogger.class.getClassLoader() != null) {
+ throw new RuntimeException("AccessSystemLogger should be loaded by the null classloader");
+ }
+ return null;
+ }
+
+ public Logger getLogger(String name) {
+ Logger logger = System.getLogger(name);
+ System.out.println("System.getLogger(\"" + name + "\"): " + logger);
+ return logger;
+ }
+
+ public Logger getLogger(String name, ResourceBundle bundle) {
+ Logger logger = System.getLogger(name, bundle);
+ System.out.println("System.getLogger(\"" + name + "\", bundle): " + logger);
+ return logger;
+ }
+
+ public java.util.logging.Logger demandSystemLogger(String name) {
+ return java.util.logging.Logger.getLogger(name);
+ }
+
+ // copy AccessSystemLogger.class to ./boot
+ public static void main(String[] args) throws IOException {
+ Path testDir = Paths.get(System.getProperty("user.dir", "."));
+ Path bootDir = Paths.get(testDir.toString(), "boot");
+ Path classes = Paths.get(System.getProperty("test.classes", "build/classes"));
+ Path thisClass = Paths.get(classes.toString(),
+ AccessSystemLogger.class.getSimpleName()+".class");
+ if (Files.notExists(bootDir)) {
+ Files.createDirectory(bootDir);
+ }
+ Path dest = Paths.get(bootDir.toString(),
+ AccessSystemLogger.class.getSimpleName()+".class");
+ Files.copy(thisClass, dest, StandardCopyOption.REPLACE_EXISTING);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/Logger/default/DefaultLoggerTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,726 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.security.AccessControlException;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.ResourceBundle;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Supplier;
+import java.lang.System.LoggerFinder;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.util.logging.Handler;
+import java.util.logging.LogRecord;
+import java.util.stream.Stream;
+
+/**
+ * @test
+ * @bug 8140364
+ * @summary Tests default loggers returned by System.getLogger, and in
+ * particular the implementation of the the System.Logger method
+ * performed by the default binding.
+ *
+ * @build DefaultLoggerTest AccessSystemLogger
+ * @run driver AccessSystemLogger
+ * @run main/othervm -Xbootclasspath/a:boot DefaultLoggerTest NOSECURITY
+ * @run main/othervm -Xbootclasspath/a:boot DefaultLoggerTest NOPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot DefaultLoggerTest WITHPERMISSIONS
+ * @author danielfuchs
+ */
+public class DefaultLoggerTest {
+
+ final static AtomicLong sequencer = new AtomicLong();
+ final static boolean VERBOSE = false;
+ static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+ static final ThreadLocal<AtomicBoolean> allowAll = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+
+ public static final Queue<LogEvent> eventQueue = new ArrayBlockingQueue<>(128);
+
+ public static final class LogEvent {
+
+ public LogEvent() {
+ this(sequencer.getAndIncrement());
+ }
+
+ LogEvent(long sequenceNumber) {
+ this.sequenceNumber = sequenceNumber;
+ }
+
+ long sequenceNumber;
+ boolean isLoggable;
+ String loggerName;
+ java.util.logging.Level level;
+ ResourceBundle bundle;
+ Throwable thrown;
+ Object[] args;
+ String msg;
+ String className;
+ String methodName;
+
+ Object[] toArray() {
+ return new Object[] {
+ sequenceNumber,
+ isLoggable,
+ loggerName,
+ level,
+ bundle,
+ thrown,
+ args,
+ msg,
+ className,
+ methodName,
+ };
+ }
+
+ @Override
+ public String toString() {
+ return Arrays.deepToString(toArray());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof LogEvent
+ && Objects.deepEquals(this.toArray(), ((LogEvent)obj).toArray());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(toArray());
+ }
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ java.util.logging.Level level, ResourceBundle bundle,
+ String key, Throwable thrown, Object... params) {
+ return LogEvent.of(sequenceNumber, isLoggable, name,
+ DefaultLoggerTest.class.getName(),
+ "testLogger", level, bundle, key,
+ thrown, params);
+ }
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ String className, String methodName,
+ java.util.logging.Level level, ResourceBundle bundle,
+ String key, Throwable thrown, Object... params) {
+ LogEvent evt = new LogEvent(sequenceNumber);
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = params;
+ evt.bundle = bundle;
+ evt.thrown = thrown;
+ evt.msg = key;
+ evt.isLoggable = isLoggable;
+ evt.className = className;
+ evt.methodName = methodName;
+ return evt;
+ }
+
+ }
+
+ static java.util.logging.Level mapToJul(Level level) {
+ switch (level) {
+ case ALL: return java.util.logging.Level.ALL;
+ case TRACE: return java.util.logging.Level.FINER;
+ case DEBUG: return java.util.logging.Level.FINE;
+ case INFO: return java.util.logging.Level.INFO;
+ case WARNING: return java.util.logging.Level.WARNING;
+ case ERROR: return java.util.logging.Level.SEVERE;
+ case OFF: return java.util.logging.Level.OFF;
+ }
+ throw new InternalError("No such level: " + level);
+ }
+
+ static void setLevel(java.util.logging.Logger sink, java.util.logging.Level loggerLevel) {
+ boolean before = allowAll.get().get();
+ try {
+ allowAll.get().set(true);
+ sink.setLevel(loggerLevel);
+ } finally {
+ allowAll.get().set(before);
+ }
+ }
+
+ public static class MyHandler extends Handler {
+
+ @Override
+ public java.util.logging.Level getLevel() {
+ return java.util.logging.Level.ALL;
+ }
+
+ @Override
+ public void publish(LogRecord record) {
+ eventQueue.add(LogEvent.of(sequencer.getAndIncrement(),
+ true, record.getLoggerName(),
+ record.getSourceClassName(),
+ record.getSourceMethodName(),
+ record.getLevel(),
+ record.getResourceBundle(), record.getMessage(),
+ record.getThrown(), record.getParameters()));
+ }
+ @Override
+ public void flush() {
+ }
+ @Override
+ public void close() throws SecurityException {
+ }
+
+ }
+ public static class MyBundle extends ResourceBundle {
+
+ final ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>();
+
+ @Override
+ protected Object handleGetObject(String key) {
+ if (key.contains(" (translated)")) {
+ throw new RuntimeException("Unexpected key: " + key);
+ }
+ return map.computeIfAbsent(key, k -> k + " (translated)");
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ return Collections.enumeration(map.keySet());
+ }
+
+ }
+ public static class MyLoggerBundle extends MyBundle {
+
+ }
+
+ static final AccessSystemLogger accessSystemLogger = new AccessSystemLogger();
+
+ static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS};
+
+ static void setSecurityManager() {
+ if (System.getSecurityManager() == null) {
+ Policy.setPolicy(new SimplePolicy(allowControl, allowAll));
+ System.setSecurityManager(new SecurityManager());
+ }
+ }
+ public static void main(String[] args) {
+ if (args.length == 0)
+ args = new String[] {
+ "NOSECURITY",
+ "NOPERMISSIONS",
+ "WITHPERMISSIONS"
+ };
+
+ // 1. Obtain destination loggers directly from the LoggerFinder
+ // - LoggerFinder.getLogger("foo", type)
+
+
+ Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> {
+ switch (testCase) {
+ case NOSECURITY:
+ System.out.println("\n*** Without Security Manager\n");
+ test(true);
+ System.out.println("Tetscase count: " + sequencer.get());
+ break;
+ case NOPERMISSIONS:
+ System.out.println("\n*** With Security Manager, without permissions\n");
+ setSecurityManager();
+ test(false);
+ System.out.println("Tetscase count: " + sequencer.get());
+ break;
+ case WITHPERMISSIONS:
+ System.out.println("\n*** With Security Manager, with control permission\n");
+ setSecurityManager();
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ test(true);
+ } finally {
+ allowControl.get().set(control);
+ }
+ break;
+ default:
+ throw new RuntimeException("Unknown test case: " + testCase);
+ }
+ });
+ System.out.println("\nPASSED: Tested " + sequencer.get() + " cases.");
+ }
+
+ public static void test(boolean hasRequiredPermissions) {
+
+ ResourceBundle loggerBundle = ResourceBundle.getBundle(MyLoggerBundle.class.getName());
+ final Map<Logger, String> loggerDescMap = new HashMap<>();
+
+
+ // 1. Test loggers returned by:
+ // - System.getLogger("foo")
+ // - and AccessSystemLogger.getLogger("foo")
+ Logger sysLogger1 = null;
+ try {
+ sysLogger1 = accessSystemLogger.getLogger("foo");
+ loggerDescMap.put(sysLogger1, "AccessSystemLogger.getLogger(\"foo\")");
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(SimplePolicy.LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ throw new RuntimeException("unexpected exception: " + acx, acx);
+ }
+
+ Logger appLogger1 = System.getLogger("foo");
+ loggerDescMap.put(appLogger1, "System.getLogger(\"foo\");");
+
+ if (appLogger1 == sysLogger1) {
+ throw new RuntimeException("identical loggers");
+ }
+
+ // 2. Test loggers returned by:
+ // - System.getLogger(\"foo\", loggerBundle)
+ // - and AccessSystemLogger.getLogger(\"foo\", loggerBundle)
+ Logger appLogger2 =
+ System.getLogger("foo", loggerBundle);
+ loggerDescMap.put(appLogger2, "System.getLogger(\"foo\", loggerBundle)");
+
+ Logger sysLogger2 = null;
+ try {
+ sysLogger2 = accessSystemLogger.getLogger("foo", loggerBundle);
+ loggerDescMap.put(sysLogger2, "AccessSystemLogger.getLogger(\"foo\", loggerBundle)");
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(SimplePolicy.LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ throw new RuntimeException("unexpected exception: " + acx, acx);
+ }
+ if (appLogger2 == sysLogger2) {
+ throw new RuntimeException("identical loggers");
+ }
+
+ final java.util.logging.Logger appSink;
+ final java.util.logging.Logger sysSink;
+ final java.util.logging.Handler appHandler;
+ final java.util.logging.Handler sysHandler;
+ final LoggerFinder provider;
+ allowAll.get().set(true);
+ try {
+ appSink = java.util.logging.Logger.getLogger("foo");
+ sysSink = accessSystemLogger.demandSystemLogger("foo");
+ appSink.addHandler(appHandler = new MyHandler());
+ sysSink.addHandler(sysHandler = new MyHandler());
+ appSink.setUseParentHandlers(false);
+ sysSink.setUseParentHandlers(false);
+ provider = LoggerFinder.getLoggerFinder();
+ } finally {
+ allowAll.get().set(false);
+ }
+ try {
+ testLogger(provider, loggerDescMap, "foo", null, sysLogger1, sysSink);
+ testLogger(provider, loggerDescMap, "foo", null, appLogger1, appSink);
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, sysLogger2, sysSink);
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, appLogger2, appSink);
+ } finally {
+ allowAll.get().set(true);
+ try {
+ appSink.removeHandler(appHandler);
+ sysSink.removeHandler(sysHandler);
+ sysSink.setLevel(null);
+ appSink.setLevel(null);
+ } finally {
+ allowAll.get().set(false);
+ }
+ }
+ }
+
+ public static class Foo {
+
+ }
+
+ static void verbose(String msg) {
+ if (VERBOSE) {
+ System.out.println(msg);
+ }
+ }
+
+ // Calls the 8 methods defined on Logger and verify the
+ // parameters received by the underlying BaseLoggerFinder.LoggerImpl
+ // logger.
+ private static void testLogger(LoggerFinder provider,
+ Map<Logger, String> loggerDescMap,
+ String name,
+ ResourceBundle loggerBundle,
+ Logger logger,
+ java.util.logging.Logger sink) {
+
+ System.out.println("Testing " + loggerDescMap.get(logger));
+
+ Foo foo = new Foo();
+ String fooMsg = foo.toString();
+ for (Level loggerLevel : Level.values()) {
+ setLevel(sink, mapToJul(loggerLevel));
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, foo): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0,
+ name, mapToJul(messageLevel), (ResourceBundle)null,
+ fooMsg, (Throwable)null, (Object[])null);
+ logger.log(messageLevel, foo);
+ if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ String msg = "blah";
+ for (Level loggerLevel : Level.values()) {
+ setLevel(sink, mapToJul(loggerLevel));
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, \"blah\"): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
+ name, mapToJul(messageLevel), loggerBundle,
+ msg, (Throwable)null, (Object[])null);
+ logger.log(messageLevel, msg);
+ if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ Supplier<String> fooSupplier = new Supplier<String>() {
+ @Override
+ public String get() {
+ return this.toString();
+ }
+ };
+
+ for (Level loggerLevel : Level.values()) {
+ setLevel(sink, mapToJul(loggerLevel));
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, fooSupplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0,
+ name, mapToJul(messageLevel), (ResourceBundle)null,
+ fooSupplier.get(),
+ (Throwable)null, (Object[])null);
+ logger.log(messageLevel, fooSupplier);
+ if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ String format = "two params [{1} {2}]";
+ Object arg1 = foo;
+ Object arg2 = msg;
+ for (Level loggerLevel : Level.values()) {
+ setLevel(sink, mapToJul(loggerLevel));
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, format, params...): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
+ name, mapToJul(messageLevel), loggerBundle,
+ format, (Throwable)null, new Object[] {arg1, arg2});
+ logger.log(messageLevel, format, arg1, arg2);
+ if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ Throwable thrown = new Exception("OK: log me!");
+ for (Level loggerLevel : Level.values()) {
+ setLevel(sink, mapToJul(loggerLevel));
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, \"blah\", thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
+ name, mapToJul(messageLevel), loggerBundle,
+ msg, thrown, (Object[]) null);
+ logger.log(messageLevel, msg, thrown);
+ if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+
+ for (Level loggerLevel : Level.values()) {
+ setLevel(sink, mapToJul(loggerLevel));
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, thrown, fooSupplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0,
+ name, mapToJul(messageLevel), (ResourceBundle)null,
+ fooSupplier.get(),
+ (Throwable)thrown, (Object[])null);
+ logger.log(messageLevel, fooSupplier, thrown);
+ if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ ResourceBundle bundle = ResourceBundle.getBundle(MyBundle.class.getName());
+ for (Level loggerLevel : Level.values()) {
+ setLevel(sink, mapToJul(loggerLevel));
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, bundle, format, params...): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
+ name, mapToJul(messageLevel), bundle,
+ format, (Throwable)null, new Object[] {foo, msg});
+ logger.log(messageLevel, bundle, format, foo, msg);
+ if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ for (Level loggerLevel : Level.values()) {
+ setLevel(sink, mapToJul(loggerLevel));
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, bundle, \"blah\", thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
+ name, mapToJul(messageLevel), bundle,
+ msg, thrown, (Object[]) null);
+ logger.log(messageLevel, bundle, msg, thrown);
+ if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+ }
+
+ final static class PermissionsBuilder {
+ final Permissions perms;
+ public PermissionsBuilder() {
+ this(new Permissions());
+ }
+ public PermissionsBuilder(Permissions perms) {
+ this.perms = perms;
+ }
+ public PermissionsBuilder add(Permission p) {
+ perms.add(p);
+ return this;
+ }
+ public PermissionsBuilder addAll(PermissionCollection col) {
+ if (col != null) {
+ for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
+ perms.add(e.nextElement());
+ }
+ }
+ return this;
+ }
+ public Permissions toPermissions() {
+ final PermissionsBuilder builder = new PermissionsBuilder();
+ builder.addAll(perms);
+ return builder.perms;
+ }
+ }
+
+ public static class SimplePolicy extends Policy {
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+ final Permissions permissions;
+ final Permissions allPermissions;
+ final Permissions controlPermissions;
+ final ThreadLocal<AtomicBoolean> allowControl;
+ final ThreadLocal<AtomicBoolean> allowAll;
+ public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl, ThreadLocal<AtomicBoolean> allowAll) {
+ this.allowControl = allowControl;
+ this.allowAll = allowAll;
+ permissions = new Permissions();
+
+ // these are used for configuring the test itself...
+ controlPermissions = new Permissions();
+ controlPermissions.add(LOGGERFINDER_PERMISSION);
+ allPermissions = new Permissions();
+ allPermissions.add(new java.security.AllPermission());
+
+ }
+
+ @Override
+ public boolean implies(ProtectionDomain domain, Permission permission) {
+ if (allowAll.get().get()) return allPermissions.implies(permission);
+ if (allowControl.get().get()) return controlPermissions.implies(permission);
+ return permissions.implies(permission);
+ }
+
+ @Override
+ public PermissionCollection getPermissions(CodeSource codesource) {
+ return new PermissionsBuilder().addAll(allowAll.get().get()
+ ? allPermissions : allowControl.get().get()
+ ? controlPermissions : permissions).toPermissions();
+ }
+
+ @Override
+ public PermissionCollection getPermissions(ProtectionDomain domain) {
+ return new PermissionsBuilder().addAll(allowAll.get().get()
+ ? allPermissions : allowControl.get().get()
+ ? controlPermissions : permissions).toPermissions();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/Logger/interface/LoggerInterfaceTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,592 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.ResourceBundle;
+import java.util.function.Consumer;
+import java.lang.System.Logger.Level;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.function.Supplier;
+
+/**
+ * @test
+ * @bug 8140364
+ * @summary Tests the default body of the System.Logger interface.
+ * @author danielfuchs
+ */
+public class LoggerInterfaceTest {
+
+ public static class LoggerImpl implements System.Logger {
+
+ public static class LogEvent implements Cloneable {
+ Level level;
+ ResourceBundle bundle;
+ String msg;
+ Throwable thrown;
+ Object[] params;
+ StackTraceElement[] callStack;
+
+ @Override
+ protected LogEvent clone() {
+ try {
+ return (LogEvent)super.clone();
+ } catch (CloneNotSupportedException x) {
+ throw new RuntimeException(x);
+ }
+ }
+
+
+ }
+
+ public static class LogEventBuilder {
+ private LogEvent event = new LogEvent();
+ public LogEventBuilder level(Level level) {
+ event.level = level;
+ return this;
+ }
+ public LogEventBuilder stack(StackTraceElement... stack) {
+ event.callStack = stack;
+ return this;
+ }
+ public LogEventBuilder bundle(ResourceBundle bundle) {
+ event.bundle = bundle;
+ return this;
+ }
+ public LogEventBuilder msg(String msg) {
+ event.msg = msg;
+ return this;
+ }
+ public LogEventBuilder thrown(Throwable thrown) {
+ event.thrown = thrown;
+ return this;
+ }
+ public LogEventBuilder params(Object... params) {
+ event.params = params;
+ return this;
+ }
+ public LogEvent build() {
+ return event.clone();
+ }
+
+ public LogEventBuilder clear() {
+ event = new LogEvent();
+ return this;
+ }
+
+ }
+
+ Level level = Level.WARNING;
+ Consumer<LogEvent> consumer;
+ final LogEventBuilder builder = new LogEventBuilder();
+
+ @Override
+ public String getName() {
+ return "noname";
+ }
+
+ @Override
+ public boolean isLoggable(Level level) {
+ return level.getSeverity() >= this.level.getSeverity();
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle, String msg, Throwable thrown) {
+ builder.clear().level(level).bundle(bundle).msg(msg).thrown(thrown)
+ .stack(new Exception().getStackTrace());
+ consumer.accept(builder.build());
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle, String format, Object... params) {
+ builder.clear().level(level).bundle(bundle).msg(format).params(params)
+ .stack(new Exception().getStackTrace());
+ consumer.accept(builder.build());
+ }
+
+ }
+
+ static class Throwing {
+ @Override
+ public String toString() {
+ throw new RuntimeException("should not have been called");
+ }
+ }
+ static class NotTrowing {
+ private final String toString;
+ private int count = 0;
+ public NotTrowing(String toString) {
+ this.toString = toString;
+ }
+
+ @Override
+ public String toString() {
+ return toString + "[" + (++count) + "]";
+ }
+ }
+
+ public static void main(String[] args) {
+ final LoggerImpl loggerImpl = new LoggerImpl();
+ final System.Logger logger = loggerImpl;
+ final Queue<LoggerImpl.LogEvent> events = new LinkedList<>();
+ loggerImpl.consumer = (x) -> events.add(x);
+
+ System.out.println("\nlogger.isLoggable(Level)");
+ assertTrue(logger.isLoggable(Level.WARNING), "logger.isLoggable(Level.WARNING)"," ");
+ assertFalse(logger.isLoggable(Level.INFO), "logger.isLoggable(Level.INFO)", " ");
+
+
+ System.out.println("\nlogger.log(Level, Object)");
+ for (Level l : Level.values()) {
+ boolean logged = l.compareTo(Level.WARNING) >= 0;
+ Object[][] cases = new Object[][] {
+ {null}, {"baz"}
+ };
+ for (Object[] p : cases) {
+ String msg = (String)p[0];
+ final Object obj = msg == null ? null : logged ? new NotTrowing(msg) : new Throwing();
+ String par1 = msg == null ? "(Object)null"
+ : logged ? "new NotTrowing(\""+ msg+"\")" : "new Throwing()";
+ System.out.println(" logger.log(" + l + ", " + par1 + ")");
+ try {
+ logger.log(l, obj);
+ if (obj == null) {
+ throw new RuntimeException("Expected NullPointerException not thrown for"
+ + " logger.log(" + l + ", " + par1 + ")");
+ }
+ } catch (NullPointerException x) {
+ if (obj == null) {
+ System.out.println(" Got expected exception: " + x);
+ continue;
+ } else {
+ throw x;
+ }
+ }
+ LoggerImpl.LogEvent e = events.poll();
+ if (logged) {
+ assertNonNull(e, "e", " ");
+ assertEquals(l, e.level, "e.level", " ");
+ assertToString(e.msg, msg, 1, "e.msg", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertEquals(e.params, null, "e.params", " ");
+ assertEquals(e.thrown, null, "e.thrown", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertEquals(e.callStack[0].getMethodName(), "log",
+ "e.callStack[0].getMethodName()", " ");
+ assertEquals(e.callStack[0].getClassName(),
+ logger.getClass().getName(),
+ "e.callStack[0].getClassName() ", " ");
+ assertEquals(e.callStack[1].getMethodName(), "log",
+ "e.callStack[1].getMethodName()", " ");
+ assertEquals(e.callStack[1].getClassName(),
+ System.Logger.class.getName(),
+ "e.callStack[1].getClassName() ", " ");
+ assertEquals(e.callStack[2].getMethodName(), "main",
+ "e.callStack[2].getMethodName()", " ");
+ } else {
+ assertEquals(e, null, "e", " ");
+ }
+ }
+ }
+ System.out.println(" logger.log(" + null + ", " +
+ "new NotThrowing(\"foobar\")" + ")");
+ try {
+ logger.log(null, new NotTrowing("foobar"));
+ throw new RuntimeException("Expected NullPointerException not thrown for"
+ + " logger.log(" + null + ", "
+ + "new NotThrowing(\"foobar\")" + ")");
+ } catch (NullPointerException x) {
+ System.out.println(" Got expected exception: " + x);
+ }
+
+
+ System.out.println("\nlogger.log(Level, String)");
+ for (Level l : Level.values()) {
+ boolean logged = l.compareTo(Level.WARNING) >= 0;
+ String par = "bar";
+ System.out.println(" logger.log(" + l + ", \"" + par +"\");");
+ logger.log(l, par);
+ LoggerImpl.LogEvent e = events.poll();
+ assertNonNull(e, "e", " ");
+ assertEquals(e.level, l, "e.level", " ");
+ assertEquals(e.msg, "bar", "e.msg", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertEquals(e.params, null, "e.params", " ");
+ assertEquals(e.thrown, null, "e.thrown", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertEquals(e.callStack[0].getMethodName(), "log",
+ "e.callStack[0].getMethodName()", " ");
+ assertEquals(e.callStack[0].getClassName(),
+ logger.getClass().getName(),
+ "e.callStack[0].getClassName() ", " ");
+ assertEquals(e.callStack[1].getMethodName(), "log",
+ "e.callStack[1].getMethodName()", " ");
+ assertEquals(e.callStack[1].getClassName(),
+ System.Logger.class.getName(),
+ "e.callStack[1].getClassName() ", " ");
+ assertEquals(e.callStack[2].getMethodName(), "main",
+ "e.callStack[2].getMethodName()", " ");
+
+ System.out.println(" logger.log(" + l + ", (String)null);");
+ logger.log(l, (String)null);
+ e = events.poll();
+ assertNonNull(e, "e", " ");
+ assertEquals(e.level, l, "e.level", " ");
+ assertEquals(e.msg, null, "e.msg", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertEquals(e.params, null, "e.params", " ");
+ assertEquals(e.thrown, null, "e.thrown", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertEquals(e.callStack[0].getMethodName(), "log",
+ "e.callStack[0].getMethodName()", " ");
+ assertEquals(e.callStack[0].getClassName(),
+ logger.getClass().getName(),
+ "e.callStack[0].getClassName() ", " ");
+ assertEquals(e.callStack[1].getMethodName(), "log",
+ "e.callStack[1].getMethodName()", " ");
+ assertEquals(e.callStack[1].getClassName(),
+ System.Logger.class.getName(),
+ "e.callStack[1].getClassName() ", " ");
+ assertEquals(e.callStack[2].getMethodName(), "main",
+ "e.callStack[2].getMethodName()", " ");
+ }
+
+ System.out.println("\nlogger.log(Level, Supplier<String>)");
+ for (Level l : Level.values()) {
+ boolean logged = l.compareTo(Level.WARNING) >= 0;
+ Object[][] cases = new Object[][] {
+ {null}, {"baz"}
+ };
+ for (Object[] p : cases) {
+ String msg = (String)p[0];
+ final Object obj = msg == null ? null : logged ? new NotTrowing(msg) : new Throwing();
+ final Supplier<String> s = msg == null ? null : () -> obj.toString();
+ String par1 = msg == null ? "(Supplier<String>)null"
+ : logged ? "() -> new NotTrowing(\""+ msg+"\").toString()" : "new Throwing()";
+ System.out.println(" logger.log(" + l + ", " + par1 + ")");
+ try {
+ logger.log(l, s);
+ if (s == null) {
+ throw new RuntimeException("Expected NullPointerException not thrown for"
+ + " logger.log(" + l + ", " + par1 + ")");
+ }
+ } catch (NullPointerException x) {
+ if (s == null) {
+ System.out.println(" Got expected exception: " + x);
+ continue;
+ } else {
+ throw x;
+ }
+ }
+ LoggerImpl.LogEvent e = events.poll();
+ if (logged) {
+ assertNonNull(e, "e", " ");
+ assertEquals(l, e.level, "e.level", " ");
+ assertToString(e.msg, msg, 1, "e.msg", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertEquals(e.params, null, "e.params", " ");
+ assertEquals(e.thrown, null, "e.thrown", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertEquals(e.callStack[0].getMethodName(), "log",
+ "e.callStack[0].getMethodName()", " ");
+ assertEquals(e.callStack[0].getClassName(),
+ logger.getClass().getName(),
+ "e.callStack[0].getClassName() ", " ");
+ assertEquals(e.callStack[1].getMethodName(), "log",
+ "e.callStack[1].getMethodName()", " ");
+ assertEquals(e.callStack[1].getClassName(),
+ System.Logger.class.getName(),
+ "e.callStack[1].getClassName() ", " ");
+ assertEquals(e.callStack[2].getMethodName(), "main",
+ "e.callStack[2].getMethodName()", " ");
+ } else {
+ assertEquals(e, null, "e", " ");
+ }
+ }
+ }
+ System.out.println(" logger.log(" + null + ", " + "() -> \"biz\"" + ")");
+ try {
+ logger.log(null, () -> "biz");
+ throw new RuntimeException("Expected NullPointerException not thrown for"
+ + " logger.log(" + null + ", "
+ + "() -> \"biz\"" + ")");
+ } catch (NullPointerException x) {
+ System.out.println(" Got expected exception: " + x);
+ }
+
+ System.out.println("\nlogger.log(Level, String, Object...)");
+ for (Level l : Level.values()) {
+ boolean logged = l.compareTo(Level.WARNING) >= 0;
+ String par = "bam";
+ Object[] params = null;
+ System.out.println(" logger.log(" + l + ", \"" + par +"\", null);");
+ logger.log(l, par, params);
+ LoggerImpl.LogEvent e = events.poll();
+ assertNonNull(e, "e", " ");
+ assertEquals(l, e.level, "e.level", " ");
+ assertEquals(e.msg, "bam", "e.msg", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertEquals(e.params, null, "e.params", " ");
+ assertEquals(e.thrown, null, "e.thrown", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertEquals(e.callStack[0].getMethodName(), "log",
+ "e.callStack[0].getMethodName()", " ");
+ assertEquals(e.callStack[0].getClassName(),
+ logger.getClass().getName(),
+ "e.callStack[0].getClassName() ", " ");
+ assertEquals(e.callStack[1].getMethodName(), "log",
+ "e.callStack[1].getMethodName()", " ");
+ assertEquals(e.callStack[1].getClassName(),
+ System.Logger.class.getName(),
+ "e.callStack[1].getClassName() ", " ");
+ assertEquals(e.callStack[2].getMethodName(), "main",
+ "e.callStack[2].getMethodName()", " ");
+
+ params = new Object[] {new NotTrowing("one")};
+ par = "bam {0}";
+ System.out.println(" logger.log(" + l + ", \"" + par
+ + "\", new NotTrowing(\"one\"));");
+ logger.log(l, par, params[0]);
+ e = events.poll();
+ assertNonNull(e, "e", " ");
+ assertEquals(l, e.level, "e.level", " ");
+ assertEquals(e.msg, par, "e.msg", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertArrayEquals(e.params, params, "e.params", " ");
+ assertEquals(e.thrown, null, "e.thrown", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertEquals(e.callStack[0].getMethodName(), "log",
+ "e.callStack[0].getMethodName()", " ");
+ assertEquals(e.callStack[0].getClassName(),
+ logger.getClass().getName(),
+ "e.callStack[0].getClassName() ", " ");
+ assertEquals(e.callStack[1].getMethodName(), "log",
+ "e.callStack[1].getMethodName()", " ");
+ assertEquals(e.callStack[1].getClassName(),
+ System.Logger.class.getName(),
+ "e.callStack[1].getClassName() ", " ");
+ assertEquals(e.callStack[2].getMethodName(), "main",
+ "e.callStack[2].getMethodName()", " ");
+
+ params = new Object[] {new NotTrowing("fisrt"), new NotTrowing("second")};
+ par = "bam {0} {1}";
+ System.out.println(" logger.log(" + l + ", \"" + par
+ + "\", new NotTrowing(\"fisrt\"),"
+ + " new NotTrowing(\"second\"));");
+ logger.log(l, par, params[0], params[1]);
+ e = events.poll();
+ assertNonNull(e, "e", " ");
+ assertEquals(l, e.level, "e.level", " ");
+ assertEquals(e.msg, par, "e.msg", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertArrayEquals(e.params, params, "e.params", " ");
+ assertEquals(e.thrown, null, "e.thrown", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertEquals(e.callStack[0].getMethodName(), "log",
+ "e.callStack[0].getMethodName()", " ");
+ assertEquals(e.callStack[0].getClassName(),
+ logger.getClass().getName(),
+ "e.callStack[0].getClassName() ", " ");
+ assertEquals(e.callStack[1].getMethodName(), "log",
+ "e.callStack[1].getMethodName()", " ");
+ assertEquals(e.callStack[1].getClassName(),
+ System.Logger.class.getName(),
+ "e.callStack[1].getClassName() ", " ");
+ assertEquals(e.callStack[2].getMethodName(), "main",
+ "e.callStack[2].getMethodName()", " ");
+
+ params = new Object[] {new NotTrowing("third"), new NotTrowing("fourth")};
+ par = "bam {2}";
+ System.out.println(" logger.log(" + l + ", \"" + par
+ + "\", new Object[] {new NotTrowing(\"third\"),"
+ + " new NotTrowing(\"fourth\")});");
+ logger.log(l, par, params);
+ e = events.poll();
+ assertNonNull(e, "e", " ");
+ assertEquals(l, e.level, "e.level", " ");
+ assertEquals(e.msg, par, "e.msg", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertArrayEquals(e.params, params, "e.params", " ");
+ assertEquals(e.thrown, null, "e.thrown", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertEquals(e.callStack[0].getMethodName(), "log",
+ "e.callStack[0].getMethodName()", " ");
+ assertEquals(e.callStack[0].getClassName(), logger.getClass().getName(),
+ "e.callStack[0].getClassName() ", " ");
+ assertEquals(e.callStack[1].getMethodName(), "log",
+ "e.callStack[1].getMethodName()", " ");
+ assertEquals(e.callStack[1].getClassName(),
+ System.Logger.class.getName(),
+ "e.callStack[1].getClassName() ", " ");
+ assertEquals(e.callStack[2].getMethodName(), "main",
+ "e.callStack[2].getMethodName()", " ");
+ }
+
+ System.out.println("\nlogger.log(Level, String, Throwable)");
+ for (Level l : Level.values()) {
+ boolean logged = l.compareTo(Level.WARNING) >= 0;
+ Object[][] cases = new Object[][] {
+ {null, null}, {null, new Throwable()}, {"biz", null}, {"boz", new Throwable()}
+ };
+ for (Object[] p : cases) {
+ String msg = (String)p[0];
+ Throwable thrown = (Throwable)p[1];
+ String par1 = msg == null ? "(String)null" : "\"" + msg + "\"";
+ String par2 = thrown == null ? "(Throwable)null" : "new Throwable()";
+ System.out.println(" logger.log(" + l + ", " + par1 +", " + par2 + ")");
+ logger.log(l, msg, thrown);
+ LoggerImpl.LogEvent e = events.poll();
+ assertNonNull(e, "e", " ");
+ assertEquals(e.level, l, "e.level", " ");
+ assertEquals(e.msg, msg, "e.msg", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertEquals(e.params, null, "e.params", " ");
+ assertEquals(e.thrown, thrown, "e.thrown", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertEquals(e.callStack[0].getMethodName(),
+ "log", "e.callStack[0].getMethodName()", " ");
+ assertEquals(e.callStack[0].getClassName(),
+ logger.getClass().getName(),
+ "e.callStack[0].getClassName() ", " ");
+ assertEquals(e.callStack[1].getMethodName(), "log",
+ "e.callStack[1].getMethodName()", " ");
+ assertEquals(e.callStack[1].getClassName(),
+ System.Logger.class.getName(),
+ "e.callStack[1].getClassName() ", " ");
+ assertEquals(e.callStack[2].getMethodName(), "main",
+ "e.callStack[2].getMethodName()", " ");
+ }
+ }
+
+ System.out.println("\nlogger.log(Level, Supplier<String>, Throwable)");
+ for (Level l : Level.values()) {
+ boolean logged = l.compareTo(Level.WARNING) >= 0;
+ Object[][] cases = new Object[][] {
+ {null, null}, {null, new Throwable()}, {"biz", null}, {"boz", new Throwable()}
+ };
+ for (Object[] p : cases) {
+ String msg = (String)p[0];
+ Throwable thrown = (Throwable)p[1];
+ final Object obj = msg == null ? null : logged ? new NotTrowing(msg) : new Throwing();
+ final Supplier<String> s = msg == null ? null : () -> obj.toString();
+ String par1 = msg == null ? "(Supplier<String>)null"
+ : logged ? "() -> new NotTrowing(\""+ msg+"\").toString()" : "new Throwing()";
+ String par2 = thrown == null ? "(Throwable)null" : "new Throwable()";
+ System.out.println(" logger.log(" + l + ", " + par1 +", " + par2 + ")");
+ try {
+ logger.log(l, s, thrown);
+ if (s== null) {
+ throw new RuntimeException("Expected NullPointerException not thrown for"
+ + " logger.log(" + l + ", " + par1 +", " + par2 + ")");
+ }
+ } catch (NullPointerException x) {
+ if (s == null) {
+ System.out.println(" Got expected exception: " + x);
+ continue;
+ } else {
+ throw x;
+ }
+ }
+ LoggerImpl.LogEvent e = events.poll();
+ if (logged) {
+ assertNonNull(e, "e", " ");
+ assertEquals(l, e.level, "e.level", " ");
+ assertToString(e.msg, msg, 1, "e.msg", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertEquals(e.params, null, "e.params", " ");
+ assertEquals(e.thrown, thrown, "e.thrown", " ");
+ assertEquals(e.bundle, null, "e.bundle", " ");
+ assertEquals(e.callStack[0].getMethodName(), "log",
+ "e.callStack[0].getMethodName()", " ");
+ assertEquals(e.callStack[0].getClassName(),
+ logger.getClass().getName(),
+ "e.callStack[0].getClassName() ", " ");
+ assertEquals(e.callStack[1].getMethodName(), "log",
+ "e.callStack[1].getMethodName()", " ");
+ assertEquals(e.callStack[1].getClassName(),
+ System.Logger.class.getName(),
+ "e.callStack[1].getClassName() ", " ");
+ assertEquals(e.callStack[2].getMethodName(), "main",
+ "e.callStack[2].getMethodName()", " ");
+ } else {
+ assertEquals(e, null, "e", " ");
+ }
+ }
+ }
+ System.out.println(" logger.log(" + null + ", " + "() -> \"biz\""
+ + ", " + "new Throwable()" + ")");
+ try {
+ logger.log(null, () -> "biz", new Throwable());
+ throw new RuntimeException("Expected NullPointerException not thrown for"
+ + " logger.log(" + null + ", "
+ + "() -> \"biz\"" + ", "
+ + "new Throwable()" + ")");
+ } catch (NullPointerException x) {
+ System.out.println(" Got expected exception: " + x);
+ }
+
+ System.out.println("Checking that we have no spurious events in the queue");
+ assertEquals(events.poll(), null, "events.poll()", " ");
+ }
+
+ static void assertTrue(boolean test, String what, String prefix) {
+ if (!test) {
+ throw new RuntimeException("Expected true for " + what);
+ }
+ System.out.println(prefix + "Got expected " + what + ": " + test);
+ }
+ static void assertFalse(boolean test, String what, String prefix) {
+ if (test) {
+ throw new RuntimeException("Expected false for " + what);
+ }
+ System.out.println(prefix + "Got expected " + what + ": " + test);
+ }
+ static void assertToString(String actual, String expected, int count, String what, String prefix) {
+ assertEquals(actual, expected + "["+count+"]", what, prefix);
+ }
+ static void assertEquals(Object actual, Object expected, String what, String prefix) {
+ if (!Objects.equals(actual, expected)) {
+ throw new RuntimeException("Bad " + what + ":"
+ + "\n\t expected: " + expected
+ + "\n\t actual: " + actual);
+ }
+ System.out.println(prefix + "Got expected " + what + ": " + actual);
+ }
+ static void assertArrayEquals(Object[] actual, Object[] expected, String what, String prefix) {
+ if (!Objects.deepEquals(actual, expected)) {
+ throw new RuntimeException("Bad " + what + ":"
+ + "\n\t expected: " + expected == null ? "null" : Arrays.deepToString(expected)
+ + "\n\t actual: " + actual == null ? "null" : Arrays.deepToString(actual));
+ }
+ System.out.println(prefix + "Got expected " + what + ": " + Arrays.deepToString(actual));
+ }
+ static void assertNonNull(Object actual, String what, String prefix) {
+ if (Objects.equals(actual, null)) {
+ throw new RuntimeException("Bad " + what + ":"
+ + "\n\t expected: non null"
+ + "\n\t actual: " + actual);
+ }
+ System.out.println(prefix + "Got expected " + what + ": " + "non null");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/AccessSystemLogger.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.IOException;
+import java.lang.System.Logger;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ResourceBundle;
+
+/**
+ *
+ * @author danielfuchs
+ */
+public final class AccessSystemLogger {
+
+ public AccessSystemLogger() {
+ this(check());
+ }
+
+ private AccessSystemLogger(Void unused) {
+ }
+
+ private static Void check() {
+ if (AccessSystemLogger.class.getClassLoader() != null) {
+ throw new RuntimeException("AccessSystemLogger should be loaded by the null classloader");
+ }
+ return null;
+ }
+
+ public Logger getLogger(String name) {
+ Logger logger = System.getLogger(name);
+ System.out.println("System.getLogger(\"" + name + "\"): " + logger);
+ return logger;
+ }
+
+ public Logger getLogger(String name, ResourceBundle bundle) {
+ Logger logger = System.getLogger(name, bundle);
+ System.out.println("System.getLogger(\"" + name + "\", bundle): " + logger);
+ return logger;
+ }
+
+ // copy AccessSystemLogger.class to ./boot
+ public static void main(String[] args) throws IOException {
+ Path testDir = Paths.get(System.getProperty("user.dir", "."));
+ Path bootDir = Paths.get(testDir.toString(), "boot");
+ Path classes = Paths.get(System.getProperty("test.classes", "build/classes"));
+ Path thisClass = Paths.get(classes.toString(),
+ AccessSystemLogger.class.getSimpleName()+".class");
+ if (Files.notExists(bootDir)) {
+ Files.createDirectory(bootDir);
+ }
+ Path dest = Paths.get(bootDir.toString(),
+ AccessSystemLogger.class.getSimpleName()+".class");
+ Files.copy(thisClass, dest, StandardCopyOption.REPLACE_EXISTING);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/BaseLoggerFinder.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.lang.System.LoggerFinder;
+import java.lang.System.Logger;
+
+public class BaseLoggerFinder extends LoggerFinder implements TestLoggerFinder {
+
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+ @Override
+ public Logger getLogger(String name, Class<?> caller) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGERFINDER_PERMISSION);
+ }
+ PrivilegedAction<ClassLoader> pa = () -> caller.getClassLoader();
+ ClassLoader callerLoader = AccessController.doPrivileged(pa);
+ if (callerLoader == null) {
+ return system.computeIfAbsent(name, (n) -> new LoggerImpl(n));
+ } else {
+ return user.computeIfAbsent(name, (n) -> new LoggerImpl(n));
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/BaseLoggerFinderTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,694 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.security.AccessControlException;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.stream.Stream;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Supplier;
+import java.lang.System.LoggerFinder;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+
+/**
+ * @test
+ * @bug 8140364
+ * @summary Tests a naive implementation of LoggerFinder, and in particular
+ * the default body of System.Logger methods.
+ * @build AccessSystemLogger BaseLoggerFinderTest CustomSystemClassLoader BaseLoggerFinder TestLoggerFinder
+ * @run driver AccessSystemLogger
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseLoggerFinderTest NOSECURITY
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseLoggerFinderTest NOPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseLoggerFinderTest WITHPERMISSIONS
+ * @author danielfuchs
+ */
+public class BaseLoggerFinderTest {
+
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+ final static boolean VERBOSE = false;
+ static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+ static final ThreadLocal<AtomicBoolean> allowAccess = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+
+ final static AccessSystemLogger accessSystemLogger = new AccessSystemLogger();
+ static final Class<?> providerClass;
+ static {
+ try {
+ providerClass = ClassLoader.getSystemClassLoader().loadClass("BaseLoggerFinder");
+ } catch (ClassNotFoundException ex) {
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+ public static class MyBundle extends ResourceBundle {
+
+ final ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>();
+
+ @Override
+ protected Object handleGetObject(String key) {
+ if (key.contains(" (translated)")) {
+ throw new RuntimeException("Unexpected key: " + key);
+ }
+ return map.computeIfAbsent(key, k -> k + " (translated)");
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ return Collections.enumeration(map.keySet());
+ }
+
+ }
+ public static class MyLoggerBundle extends MyBundle {
+
+ }
+
+ static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS};
+
+ static void setSecurityManager() {
+ if (System.getSecurityManager() == null) {
+ Policy.setPolicy(new SimplePolicy(allowControl, allowAccess));
+ System.setSecurityManager(new SecurityManager());
+ }
+ }
+
+ public static void main(String[] args) {
+ if (args.length == 0)
+ args = new String[] {
+ //"NOSECURITY",
+ "NOPERMISSIONS",
+ "WITHPERMISSIONS"
+ };
+
+ System.out.println("Using provider class: " + providerClass + "[" + providerClass.getClassLoader() + "]");
+
+ Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> {
+ TestLoggerFinder provider;
+ switch (testCase) {
+ case NOSECURITY:
+ System.out.println("\n*** Without Security Manager\n");
+ provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
+ test(provider, true);
+ System.out.println("Tetscase count: " + TestLoggerFinder.sequencer.get());
+ break;
+ case NOPERMISSIONS:
+ System.out.println("\n*** With Security Manager, without permissions\n");
+ setSecurityManager();
+ try {
+ provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
+ throw new RuntimeException("Expected exception not raised");
+ } catch (AccessControlException x) {
+ if (!LOGGERFINDER_PERMISSION.equals(x.getPermission())) {
+ throw new RuntimeException("Unexpected permission check", x);
+ }
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
+ } finally {
+ allowControl.get().set(control);
+ }
+ }
+ test(provider, false);
+ System.out.println("Tetscase count: " + TestLoggerFinder.sequencer.get());
+ break;
+ case WITHPERMISSIONS:
+ System.out.println("\n*** With Security Manager, with control permission\n");
+ setSecurityManager();
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
+ test(provider, true);
+ } finally {
+ allowControl.get().set(control);
+ }
+ break;
+ default:
+ throw new RuntimeException("Unknown test case: " + testCase);
+ }
+ });
+ System.out.println("\nPASSED: Tested " + TestLoggerFinder.sequencer.get() + " cases.");
+ }
+
+ public static void test(TestLoggerFinder provider, boolean hasRequiredPermissions) {
+
+ ResourceBundle loggerBundle = ResourceBundle.getBundle(MyLoggerBundle.class.getName());
+ final Map<Logger, String> loggerDescMap = new HashMap<>();
+
+
+ // 1. Test loggers returned by LoggerFinder, both for system callers
+ // and not system callers.
+ TestLoggerFinder.LoggerImpl appLogger1 = null;
+ try {
+ appLogger1 =
+ TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", BaseLoggerFinderTest.class));
+ loggerDescMap.put(appLogger1, "provider.getLogger(\"foo\", BaseLoggerFinderTest.class)");
+ if (!hasRequiredPermissions) {
+ throw new RuntimeException("Managed to obtain a logger without permission");
+ }
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ System.out.println("Got expected exception for logger: " + acx);
+ final boolean old = allowControl.get().get();
+ allowControl.get().set(true);
+ try {
+ appLogger1 =
+ TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", BaseLoggerFinderTest.class));
+ loggerDescMap.put(appLogger1, "provider.getLogger(\"foo\", BaseLoggerFinderTest.class)");
+ } finally {
+ allowControl.get().set(old);
+ }
+ }
+
+ TestLoggerFinder.LoggerImpl sysLogger1 = null;
+ try {
+ sysLogger1 = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class));
+ loggerDescMap.put(sysLogger1, "provider.getLogger(\"foo\", Thread.class)");
+ if (!hasRequiredPermissions) {
+ throw new RuntimeException("Managed to obtain a system logger without permission");
+ }
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ System.out.println("Got expected exception for system logger: " + acx);
+ final boolean old = allowControl.get().get();
+ allowControl.get().set(true);
+ try {
+ sysLogger1 = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class));
+ loggerDescMap.put(sysLogger1, "provider.getLogger(\"foo\", Thread.class)");
+ } finally {
+ allowControl.get().set(old);
+ }
+ }
+ if (appLogger1 == sysLogger1) {
+ throw new RuntimeException("identical loggers");
+ }
+
+ if (provider.system.contains(appLogger1)) {
+ throw new RuntimeException("app logger in system map");
+ }
+ if (!provider.user.contains(appLogger1)) {
+ throw new RuntimeException("app logger not in appplication map");
+ }
+ if (provider.user.contains(sysLogger1)) {
+ throw new RuntimeException("sys logger in appplication map");
+ }
+ if (!provider.system.contains(sysLogger1)) {
+ throw new RuntimeException("sys logger not in system map");
+ }
+
+ testLogger(provider, loggerDescMap, "foo", null, appLogger1, appLogger1);
+ testLogger(provider, loggerDescMap, "foo", null, sysLogger1, sysLogger1);
+
+ // 2. Test localized loggers returned LoggerFinder, both for system
+ // callers and non system callers
+ Logger appLogger2 = null;
+ try {
+ appLogger2 = provider.getLocalizedLogger("foo", loggerBundle, BaseLoggerFinderTest.class);
+ loggerDescMap.put(appLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, BaseLoggerFinderTest.class)");
+ if (!hasRequiredPermissions) {
+ throw new RuntimeException("Managed to obtain a logger without permission");
+ }
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ System.out.println("Got expected exception for logger: " + acx);
+ final boolean old = allowControl.get().get();
+ allowControl.get().set(true);
+ try {
+ appLogger2 = provider.getLocalizedLogger("foo", loggerBundle, BaseLoggerFinderTest.class);
+ loggerDescMap.put(appLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, BaseLoggerFinderTest.class)");
+ } finally {
+ allowControl.get().set(old);
+ }
+ }
+
+ Logger sysLogger2 = null;
+ try {
+ sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class);
+ loggerDescMap.put(sysLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, Thread.class)");
+ if (!hasRequiredPermissions) {
+ throw new RuntimeException("Managed to obtain a system logger without permission");
+ }
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ System.out.println("Got expected exception for localized system logger: " + acx);
+ final boolean old = allowControl.get().get();
+ allowControl.get().set(true);
+ try {
+ sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class);
+ loggerDescMap.put(sysLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, Thread.class))");
+ } finally {
+ allowControl.get().set(old);
+ }
+ }
+ if (appLogger2 == sysLogger2) {
+ throw new RuntimeException("identical loggers");
+ }
+ if (appLogger2 == appLogger1) {
+ throw new RuntimeException("identical loggers");
+ }
+ if (sysLogger2 == sysLogger1) {
+ throw new RuntimeException("identical loggers");
+ }
+
+ if (provider.system.contains(appLogger2)) {
+ throw new RuntimeException("localized app logger in system map");
+ }
+ if (provider.user.contains(appLogger2)) {
+ throw new RuntimeException("localized app logger in appplication map");
+ }
+ if (provider.user.contains(sysLogger2)) {
+ throw new RuntimeException("localized sys logger in appplication map");
+ }
+ if (provider.system.contains(sysLogger2)) {
+ throw new RuntimeException("localized sys logger not in system map");
+ }
+
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, appLogger2, appLogger1);
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, sysLogger2, sysLogger1);
+
+ // 3 Test loggers returned by:
+ // 3.1: System.getLogger("foo")
+ Logger appLogger3 = System.getLogger("foo");
+ loggerDescMap.put(appLogger3, "System.getLogger(\"foo\")");
+ testLogger(provider, loggerDescMap, "foo", null, appLogger3, appLogger1);
+
+ // 3.2: System.getLogger("foo")
+ // Emulate what System.getLogger() does when the caller is a
+ // platform classes
+ Logger sysLogger3 = accessSystemLogger.getLogger("foo");
+ loggerDescMap.put(sysLogger3, "AccessSystemLogger.getLogger(\"foo\")");
+
+ if (appLogger3 == sysLogger3) {
+ throw new RuntimeException("identical loggers");
+ }
+
+ testLogger(provider, loggerDescMap, "foo", null, sysLogger3, sysLogger1);
+
+ // 4. Test loggers returned by:
+ // 4.1 System.getLogger("foo", loggerBundle)
+ Logger appLogger4 =
+ System.getLogger("foo", loggerBundle);
+ loggerDescMap.put(appLogger4, "System.getLogger(\"foo\", loggerBundle)");
+ if (appLogger4 == appLogger1) {
+ throw new RuntimeException("identical loggers");
+ }
+
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, appLogger4, appLogger1);
+
+ // 4.2: System.getLogger("foo", loggerBundle)
+ // Emulate what System.getLogger() does when the caller is a
+ // platform classes
+ Logger sysLogger4 = accessSystemLogger.getLogger("foo", loggerBundle);
+ loggerDescMap.put(sysLogger4, "AccessSystemLogger.getLogger(\"foo\", loggerBundle)");
+ if (appLogger4 == sysLogger4) {
+ throw new RuntimeException("identical loggers");
+ }
+
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, sysLogger4, sysLogger1);
+
+ }
+
+ public static class Foo {
+
+ }
+
+ static void verbose(String msg) {
+ if (VERBOSE) {
+ System.out.println(msg);
+ }
+ }
+
+ // Calls the 8 methods defined on Logger and verify the
+ // parameters received by the underlying TestProvider.LoggerImpl
+ // logger.
+ private static void testLogger(TestLoggerFinder provider,
+ Map<Logger, String> loggerDescMap,
+ String name,
+ ResourceBundle loggerBundle,
+ Logger logger,
+ TestLoggerFinder.LoggerImpl sink) {
+
+ System.out.println("Testing " + loggerDescMap.get(logger) + " [" + logger +"]");
+ AtomicLong sequencer = TestLoggerFinder.sequencer;
+
+ Foo foo = new Foo();
+ String fooMsg = foo.toString();
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, foo): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0,
+ name, messageLevel, (ResourceBundle)null,
+ fooMsg, null, (Throwable)null, (Object[])null);
+ logger.log(messageLevel, foo);
+ if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (provider.eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ TestLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ String msg = "blah";
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, \"blah\"): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
+ name, messageLevel, loggerBundle,
+ msg, null, (Throwable)null, (Object[])null);
+ logger.log(messageLevel, msg);
+ TestLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+
+ Supplier<String> fooSupplier = new Supplier<String>() {
+ @Override
+ public String get() {
+ return this.toString();
+ }
+ };
+
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, fooSupplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0,
+ name, messageLevel, (ResourceBundle)null,
+ fooSupplier.get(), null,
+ (Throwable)null, (Object[])null);
+ logger.log(messageLevel, fooSupplier);
+ if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (provider.eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ TestLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ String format = "two params [{1} {2}]";
+ Object arg1 = foo;
+ Object arg2 = msg;
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, format, params...): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
+ name, messageLevel, loggerBundle,
+ format, null, (Throwable)null, new Object[] {foo, msg});
+ logger.log(messageLevel, format, foo, msg);
+ TestLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+
+ Throwable thrown = new Exception("OK: log me!");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, \"blah\", thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
+ name, messageLevel, loggerBundle,
+ msg, null, thrown, (Object[]) null);
+ logger.log(messageLevel, msg, thrown);
+ TestLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+
+
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, thrown, fooSupplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0,
+ name, messageLevel, (ResourceBundle)null,
+ fooSupplier.get(), null,
+ (Throwable)thrown, (Object[])null);
+ logger.log(messageLevel, fooSupplier, thrown);
+ if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (provider.eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ TestLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ ResourceBundle bundle = ResourceBundle.getBundle(MyBundle.class.getName());
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, bundle, format, params...): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
+ name, messageLevel, bundle,
+ format, null, (Throwable)null, new Object[] {foo, msg});
+ logger.log(messageLevel, bundle, format, foo, msg);
+ TestLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, bundle, \"blah\", thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
+ name, messageLevel, bundle,
+ msg, null, thrown, (Object[]) null);
+ logger.log(messageLevel, bundle, msg, thrown);
+ TestLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ final static class PermissionsBuilder {
+ final Permissions perms;
+ public PermissionsBuilder() {
+ this(new Permissions());
+ }
+ public PermissionsBuilder(Permissions perms) {
+ this.perms = perms;
+ }
+ public PermissionsBuilder add(Permission p) {
+ perms.add(p);
+ return this;
+ }
+ public PermissionsBuilder addAll(PermissionCollection col) {
+ if (col != null) {
+ for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
+ perms.add(e.nextElement());
+ }
+ }
+ return this;
+ }
+ public Permissions toPermissions() {
+ final PermissionsBuilder builder = new PermissionsBuilder();
+ builder.addAll(perms);
+ return builder.perms;
+ }
+ }
+
+ public static class SimplePolicy extends Policy {
+ final static RuntimePermission CONTROL = LOGGERFINDER_PERMISSION;
+ final static RuntimePermission ACCESS = new RuntimePermission("accessClassInPackage.jdk.internal.logger");
+
+ final Permissions permissions;
+ final ThreadLocal<AtomicBoolean> allowControl;
+ final ThreadLocal<AtomicBoolean> allowAccess;
+ public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl, ThreadLocal<AtomicBoolean> allowAccess) {
+ this.allowControl = allowControl;
+ this.allowAccess = allowAccess;
+ permissions = new Permissions();
+ }
+
+ Permissions getPermissions() {
+ if (allowControl.get().get() || allowAccess.get().get()) {
+ PermissionsBuilder builder = new PermissionsBuilder()
+ .addAll(permissions);
+ if (allowControl.get().get()) {
+ builder.add(CONTROL);
+ }
+ if (allowAccess.get().get()) {
+ builder.add(ACCESS);
+ }
+ return builder.toPermissions();
+ }
+ return permissions;
+ }
+
+ @Override
+ public boolean implies(ProtectionDomain domain, Permission permission) {
+ return getPermissions().implies(permission);
+ }
+
+ @Override
+ public PermissionCollection getPermissions(CodeSource codesource) {
+ return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
+ }
+
+ @Override
+ public PermissionCollection getPermissions(ProtectionDomain domain) {
+ return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/CustomSystemClassLoader.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.security.AllPermission;
+import java.security.Permissions;
+import java.security.ProtectionDomain;
+
+
+/**
+ * A custom ClassLoader to load the concrete LoggerFinder class
+ * with all permissions.
+ *
+ * @author danielfuchs
+ */
+public class CustomSystemClassLoader extends ClassLoader {
+
+
+ Class<?> finderClass = null;
+
+ public CustomSystemClassLoader() {
+ super();
+ }
+ public CustomSystemClassLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ private Class<?> defineFinderClass(String name)
+ throws ClassNotFoundException {
+ final Object obj = getClassLoadingLock(name);
+ synchronized(obj) {
+ if (finderClass != null) return finderClass;
+
+ URL url = this.getClass().getProtectionDomain().getCodeSource().getLocation();
+ File file = new File(url.getPath(), name+".class");
+ if (file.canRead()) {
+ try {
+ byte[] b = Files.readAllBytes(file.toPath());
+ Permissions perms = new Permissions();
+ perms.add(new AllPermission());
+ finderClass = defineClass(
+ name, b, 0, b.length, new ProtectionDomain(
+ this.getClass().getProtectionDomain().getCodeSource(),
+ perms));
+ System.out.println("Loaded " + name);
+ return finderClass;
+ } catch (Throwable ex) {
+ ex.printStackTrace();
+ throw new ClassNotFoundException(name, ex);
+ }
+ } else {
+ throw new ClassNotFoundException(name,
+ new IOException(file.toPath() + ": can't read"));
+ }
+ }
+ }
+
+ @Override
+ public synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ if (name.equals("BaseLoggerFinder")) {
+ Class<?> c = defineFinderClass(name);
+ if (resolve) {
+ resolveClass(c);
+ }
+ return c;
+ }
+ return super.loadClass(name, resolve);
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ if (name.equals("BaseLoggerFinder")) {
+ return defineFinderClass(name);
+ }
+ return super.findClass(name);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/META-INF/services/java.lang.System$LoggerFinder Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,1 @@
+BaseLoggerFinder
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/TestLoggerFinder.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.ResourceBundle;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Supplier;
+import java.lang.System.Logger;
+
+/**
+ * What our test provider needs to implement.
+ * @author danielfuchs
+ */
+public interface TestLoggerFinder {
+ public final static AtomicLong sequencer = new AtomicLong();
+ public final ConcurrentHashMap<String, LoggerImpl> system = new ConcurrentHashMap<>();
+ public final ConcurrentHashMap<String, LoggerImpl> user = new ConcurrentHashMap<>();
+ public final Queue<LogEvent> eventQueue = new ArrayBlockingQueue<>(128);
+
+ public static final class LogEvent {
+
+ public LogEvent() {
+ this(sequencer.getAndIncrement());
+ }
+
+ LogEvent(long sequenceNumber) {
+ this.sequenceNumber = sequenceNumber;
+ }
+
+ long sequenceNumber;
+ boolean isLoggable;
+ String loggerName;
+ Logger.Level level;
+ ResourceBundle bundle;
+ Throwable thrown;
+ Object[] args;
+ Supplier<String> supplier;
+ String msg;
+
+ Object[] toArray() {
+ return new Object[] {
+ sequenceNumber,
+ isLoggable,
+ loggerName,
+ level,
+ bundle,
+ thrown,
+ args,
+ supplier,
+ msg,
+ };
+ }
+
+ @Override
+ public String toString() {
+ return Arrays.deepToString(toArray());
+ }
+
+
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof LogEvent
+ && Objects.deepEquals(this.toArray(), ((LogEvent)obj).toArray());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(toArray());
+ }
+
+
+ public static LogEvent of(boolean isLoggable, String name,
+ Logger.Level level, ResourceBundle bundle,
+ String key, Throwable thrown) {
+ LogEvent evt = new LogEvent();
+ evt.isLoggable = isLoggable;
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = null;
+ evt.bundle = bundle;
+ evt.thrown = thrown;
+ evt.supplier = null;
+ evt.msg = key;
+ return evt;
+ }
+
+ public static LogEvent of(boolean isLoggable, String name,
+ Logger.Level level, ResourceBundle bundle,
+ String key, Object... params) {
+ LogEvent evt = new LogEvent();
+ evt.isLoggable = isLoggable;
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = params;
+ evt.bundle = bundle;
+ evt.thrown = null;
+ evt.supplier = null;
+ evt.msg = key;
+ return evt;
+ }
+
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ Logger.Level level, ResourceBundle bundle,
+ String key, Supplier<String> supplier,
+ Throwable thrown, Object... params) {
+ LogEvent evt = new LogEvent(sequenceNumber);
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = params;
+ evt.bundle = bundle;
+ evt.thrown = thrown;
+ evt.supplier = supplier;
+ evt.msg = key;
+ evt.isLoggable = isLoggable;
+ return evt;
+ }
+
+ }
+
+ public class LoggerImpl implements Logger {
+ final String name;
+ Logger.Level level = Logger.Level.INFO;
+
+ public LoggerImpl(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean isLoggable(Logger.Level level) {
+ return this.level != Logger.Level.OFF && this.level.getSeverity() <= level.getSeverity();
+ }
+
+ @Override
+ public void log(Logger.Level level, ResourceBundle bundle, String key, Throwable thrown) {
+ log(LogEvent.of(isLoggable(level), this.name, level, bundle, key, thrown));
+ }
+
+ @Override
+ public void log(Logger.Level level, ResourceBundle bundle, String format, Object... params) {
+ log(LogEvent.of(isLoggable(level), name, level, bundle, format, params));
+ }
+
+ void log(LogEvent event) {
+ eventQueue.add(event);
+ }
+ }
+
+ public Logger getLogger(String name, Class<?> caller);
+ public Logger getLocalizedLogger(String name, ResourceBundle bundle, Class<?> caller);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/DefaultLoggerFinderTest/AccessSystemLogger.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.IOException;
+import java.lang.System.Logger;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ResourceBundle;
+
+/**
+ *
+ * @author danielfuchs
+ */
+public final class AccessSystemLogger {
+
+ public AccessSystemLogger() {
+ this(check());
+ }
+
+ private AccessSystemLogger(Void unused) {
+ }
+
+ private static Void check() {
+ if (AccessSystemLogger.class.getClassLoader() != null) {
+ throw new RuntimeException("AccessSystemLogger should be loaded by the null classloader");
+ }
+ return null;
+ }
+
+ public Logger getLogger(String name) {
+ Logger logger = System.getLogger(name);
+ System.out.println("System.getLogger(\"" + name + "\"): " + logger);
+ return logger;
+ }
+
+ public Logger getLogger(String name, ResourceBundle bundle) {
+ Logger logger = System.getLogger(name, bundle);
+ System.out.println("System.getLogger(\"" + name + "\", bundle): " + logger);
+ return logger;
+ }
+
+ public java.util.logging.Logger demandSystemLogger(String name) {
+ return java.util.logging.Logger.getLogger(name);
+ }
+
+ // copy AccessSystemLogger.class to ./boot
+ public static void main(String[] args) throws IOException {
+ Path testDir = Paths.get(System.getProperty("user.dir", "."));
+ Path bootDir = Paths.get(testDir.toString(), "boot");
+ Path classes = Paths.get(System.getProperty("test.classes", "build/classes"));
+ Path thisClass = Paths.get(classes.toString(),
+ AccessSystemLogger.class.getSimpleName()+".class");
+ if (Files.notExists(bootDir)) {
+ Files.createDirectory(bootDir);
+ }
+ Path dest = Paths.get(bootDir.toString(),
+ AccessSystemLogger.class.getSimpleName()+".class");
+ Files.copy(thisClass, dest, StandardCopyOption.REPLACE_EXISTING);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/DefaultLoggerFinderTest/DefaultLoggerFinderTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,887 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.security.AccessControlException;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.ResourceBundle;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Supplier;
+import java.util.logging.Handler;
+import java.util.logging.LogRecord;
+import java.lang.System.LoggerFinder;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.util.stream.Stream;
+
+/**
+ * @test
+ * @bug 8140364
+ * @summary Tests the default implementation of System.Logger, when
+ * JUL is the default backend.
+ * @build AccessSystemLogger DefaultLoggerFinderTest
+ * @run driver AccessSystemLogger
+ * @run main/othervm -Xbootclasspath/a:boot DefaultLoggerFinderTest NOSECURITY
+ * @run main/othervm -Xbootclasspath/a:boot DefaultLoggerFinderTest NOPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot DefaultLoggerFinderTest WITHPERMISSIONS
+ * @author danielfuchs
+ */
+public class DefaultLoggerFinderTest {
+
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+ final static AtomicLong sequencer = new AtomicLong();
+ final static boolean VERBOSE = false;
+ static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+ static final ThreadLocal<AtomicBoolean> allowAll = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+
+ static final AccessSystemLogger accessSystemLogger = new AccessSystemLogger();
+
+ public static final Queue<LogEvent> eventQueue = new ArrayBlockingQueue<>(128);
+
+ public static final class LogEvent {
+
+ public LogEvent() {
+ this(sequencer.getAndIncrement());
+ }
+
+ LogEvent(long sequenceNumber) {
+ this.sequenceNumber = sequenceNumber;
+ }
+
+ long sequenceNumber;
+ boolean isLoggable;
+ String loggerName;
+ java.util.logging.Level level;
+ ResourceBundle bundle;
+ Throwable thrown;
+ Object[] args;
+ String msg;
+ String className;
+ String methodName;
+
+ Object[] toArray() {
+ return new Object[] {
+ sequenceNumber,
+ isLoggable,
+ loggerName,
+ level,
+ bundle,
+ thrown,
+ args,
+ msg,
+ className,
+ methodName,
+ };
+ }
+
+ @Override
+ public String toString() {
+ return Arrays.deepToString(toArray());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof LogEvent
+ && Objects.deepEquals(this.toArray(), ((LogEvent)obj).toArray());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(toArray());
+ }
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ java.util.logging.Level level, ResourceBundle bundle,
+ String key, Throwable thrown, Object... params) {
+ return LogEvent.of(sequenceNumber, isLoggable, name,
+ DefaultLoggerFinderTest.class.getName(),
+ "testLogger", level, bundle, key,
+ thrown, params);
+ }
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ String className, String methodName,
+ java.util.logging.Level level, ResourceBundle bundle,
+ String key, Throwable thrown, Object... params) {
+ LogEvent evt = new LogEvent(sequenceNumber);
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = params;
+ evt.bundle = bundle;
+ evt.thrown = thrown;
+ evt.msg = key;
+ evt.isLoggable = isLoggable;
+ evt.className = className;
+ evt.methodName = methodName;
+ return evt;
+ }
+
+ }
+
+ static java.util.logging.Level mapToJul(Level level) {
+ switch (level) {
+ case ALL: return java.util.logging.Level.ALL;
+ case TRACE: return java.util.logging.Level.FINER;
+ case DEBUG: return java.util.logging.Level.FINE;
+ case INFO: return java.util.logging.Level.INFO;
+ case WARNING: return java.util.logging.Level.WARNING;
+ case ERROR: return java.util.logging.Level.SEVERE;
+ case OFF: return java.util.logging.Level.OFF;
+ }
+ throw new InternalError("No such level: " + level);
+ }
+
+ static final java.util.logging.Level[] julLevels = {
+ java.util.logging.Level.ALL,
+ new java.util.logging.Level("FINER_THAN_FINEST", java.util.logging.Level.FINEST.intValue() - 10) {},
+ java.util.logging.Level.FINEST,
+ new java.util.logging.Level("FINER_THAN_FINER", java.util.logging.Level.FINER.intValue() - 10) {},
+ java.util.logging.Level.FINER,
+ new java.util.logging.Level("FINER_THAN_FINE", java.util.logging.Level.FINE.intValue() - 10) {},
+ java.util.logging.Level.FINE,
+ new java.util.logging.Level("FINER_THAN_CONFIG", java.util.logging.Level.FINE.intValue() + 10) {},
+ java.util.logging.Level.CONFIG,
+ new java.util.logging.Level("FINER_THAN_INFO", java.util.logging.Level.INFO.intValue() - 10) {},
+ java.util.logging.Level.INFO,
+ new java.util.logging.Level("FINER_THAN_WARNING", java.util.logging.Level.INFO.intValue() + 10) {},
+ java.util.logging.Level.WARNING,
+ new java.util.logging.Level("FINER_THAN_SEVERE", java.util.logging.Level.SEVERE.intValue() - 10) {},
+ java.util.logging.Level.SEVERE,
+ new java.util.logging.Level("FATAL", java.util.logging.Level.SEVERE.intValue() + 10) {},
+ java.util.logging.Level.OFF,
+ };
+
+ static final Level[] mappedLevels = {
+ Level.ALL, // ALL
+ Level.DEBUG, // FINER_THAN_FINEST
+ Level.DEBUG, // FINEST
+ Level.DEBUG, // FINER_THAN_FINER
+ Level.TRACE, // FINER
+ Level.TRACE, // FINER_THAN_FINE
+ Level.DEBUG, // FINE
+ Level.DEBUG, // FINER_THAN_CONFIG
+ Level.DEBUG, // CONFIG
+ Level.DEBUG, // FINER_THAN_INFO
+ Level.INFO, // INFO
+ Level.INFO, // FINER_THAN_WARNING
+ Level.WARNING, // WARNING
+ Level.WARNING, // FINER_THAN_SEVERE
+ Level.ERROR, // SEVERE
+ Level.ERROR, // FATAL
+ Level.OFF, // OFF
+ };
+
+ final static Map<java.util.logging.Level, Level> julToSpiMap;
+ static {
+ Map<java.util.logging.Level, Level> map = new HashMap<>();
+ if (mappedLevels.length != julLevels.length) {
+ throw new ExceptionInInitializerError("Array lengths differ"
+ + "\n\tjulLevels=" + Arrays.deepToString(julLevels)
+ + "\n\tmappedLevels=" + Arrays.deepToString(mappedLevels));
+ }
+ for (int i=0; i<julLevels.length; i++) {
+ map.put(julLevels[i], mappedLevels[i]);
+ }
+ julToSpiMap = Collections.unmodifiableMap(map);
+ }
+
+ public static class MyBundle extends ResourceBundle {
+
+ final ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>();
+
+ @Override
+ protected Object handleGetObject(String key) {
+ if (key.contains(" (translated)")) {
+ throw new RuntimeException("Unexpected key: " + key);
+ }
+ return map.computeIfAbsent(key, k -> k + " (translated)");
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ return Collections.enumeration(map.keySet());
+ }
+
+ }
+
+ public static class MyHandler extends Handler {
+
+ @Override
+ public java.util.logging.Level getLevel() {
+ return java.util.logging.Level.ALL;
+ }
+
+ @Override
+ public void publish(LogRecord record) {
+ eventQueue.add(LogEvent.of(sequencer.getAndIncrement(),
+ true, record.getLoggerName(),
+ record.getSourceClassName(),
+ record.getSourceMethodName(),
+ record.getLevel(),
+ record.getResourceBundle(), record.getMessage(),
+ record.getThrown(), record.getParameters()));
+ }
+ @Override
+ public void flush() {
+ }
+ @Override
+ public void close() throws SecurityException {
+ }
+
+ }
+
+ public static class MyLoggerBundle extends MyBundle {
+
+ }
+
+
+ static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS};
+
+ static void setSecurityManager() {
+ if (System.getSecurityManager() == null) {
+ Policy.setPolicy(new SimplePolicy(allowAll, allowControl));
+ System.setSecurityManager(new SecurityManager());
+ }
+ }
+
+ public static void main(String[] args) {
+ if (args.length == 0)
+ args = new String[] {
+ "NOSECURITY",
+ "NOPERMISSIONS",
+ "WITHPERMISSIONS"
+ };
+
+ final java.util.logging.Logger appSink = java.util.logging.Logger.getLogger("foo");
+ final java.util.logging.Logger sysSink = accessSystemLogger.demandSystemLogger("foo");
+ appSink.addHandler(new MyHandler());
+ sysSink.addHandler(new MyHandler());
+ appSink.setUseParentHandlers(VERBOSE);
+ sysSink.setUseParentHandlers(VERBOSE);
+
+ Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> {
+ LoggerFinder provider;
+ switch (testCase) {
+ case NOSECURITY:
+ System.out.println("\n*** Without Security Manager\n");
+ provider = LoggerFinder.getLoggerFinder();
+ test(provider, true, appSink, sysSink);
+ System.out.println("Tetscase count: " + sequencer.get());
+ break;
+ case NOPERMISSIONS:
+ System.out.println("\n*** With Security Manager, without permissions\n");
+ setSecurityManager();
+ try {
+ provider = LoggerFinder.getLoggerFinder();
+ throw new RuntimeException("Expected exception not raised");
+ } catch (AccessControlException x) {
+ if (!LOGGERFINDER_PERMISSION.equals(x.getPermission())) {
+ throw new RuntimeException("Unexpected permission check", x);
+ }
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = LoggerFinder.getLoggerFinder();
+ } finally {
+ allowControl.get().set(control);
+ }
+ }
+ test(provider, false, appSink, sysSink);
+ System.out.println("Tetscase count: " + sequencer.get());
+ break;
+ case WITHPERMISSIONS:
+ System.out.println("\n*** With Security Manager, with control permission\n");
+ setSecurityManager();
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = LoggerFinder.getLoggerFinder();
+ test(provider, true, appSink, sysSink);
+ } finally {
+ allowControl.get().set(control);
+ }
+ break;
+ default:
+ throw new RuntimeException("Unknown test case: " + testCase);
+ }
+ });
+ System.out.println("\nPASSED: Tested " + sequencer.get() + " cases.");
+ }
+
+ public static void test(LoggerFinder provider,
+ boolean hasRequiredPermissions,
+ java.util.logging.Logger appSink,
+ java.util.logging.Logger sysSink) {
+
+ ResourceBundle loggerBundle = ResourceBundle.getBundle(MyLoggerBundle.class.getName());
+ final Map<Logger, String> loggerDescMap = new HashMap<>();
+
+
+ Logger appLogger1 = null;
+ try {
+ appLogger1 = provider.getLogger("foo", DefaultLoggerFinderTest.class);
+ loggerDescMap.put(appLogger1, "provider.getApplicationLogger(\"foo\")");
+ if (!hasRequiredPermissions) {
+ throw new RuntimeException("Managed to obtain a logger without permission");
+ }
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ System.out.println("Got expected exception for logger: " + acx);
+ boolean old = allowControl.get().get();
+ allowControl.get().set(true);
+ try {
+ appLogger1 =provider.getLogger("foo", DefaultLoggerFinderTest.class);
+ loggerDescMap.put(appLogger1, "provider.getApplicationLogger(\"foo\")");
+ } finally {
+ allowControl.get().set(old);
+ }
+ }
+
+ Logger sysLogger1 = null;
+ try {
+ sysLogger1 = provider.getLogger("foo", Thread.class);
+ loggerDescMap.put(sysLogger1, "provider.getSystemLogger(\"foo\")");
+ if (!hasRequiredPermissions) {
+ throw new RuntimeException("Managed to obtain a system logger without permission");
+ }
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ System.out.println("Got expected exception for system logger: " + acx);
+ boolean old = allowControl.get().get();
+ allowControl.get().set(true);
+ try {
+ sysLogger1 = provider.getLogger("foo", Thread.class);
+ loggerDescMap.put(sysLogger1, "provider.getSystemLogger(\"foo\")");
+ } finally {
+ allowControl.get().set(old);
+ }
+ }
+ if (appLogger1 == sysLogger1) {
+ throw new RuntimeException("identical loggers");
+ }
+
+ Logger appLogger2 = null;
+ try {
+ appLogger2 = provider.getLocalizedLogger("foo", loggerBundle, DefaultLoggerFinderTest.class);
+ loggerDescMap.put(appLogger2, "provider.getLocalizedApplicationLogger(\"foo\", loggerBundle)");
+ if (!hasRequiredPermissions) {
+ throw new RuntimeException("Managed to obtain a logger without permission");
+ }
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ System.out.println("Got expected exception for logger: " + acx);
+ boolean old = allowControl.get().get();
+ allowControl.get().set(true);
+ try {
+ appLogger2 = provider.getLocalizedLogger("foo", loggerBundle, DefaultLoggerFinderTest.class);
+ loggerDescMap.put(appLogger2, "provider.getLocalizedApplicationLogger(\"foo\", loggerBundle)");
+ } finally {
+ allowControl.get().set(old);
+ }
+ }
+
+ Logger sysLogger2 = null;
+ try {
+ sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class);
+ loggerDescMap.put(sysLogger2, "provider.getLocalizedSystemLogger(\"foo\", loggerBundle)");
+ if (!hasRequiredPermissions) {
+ throw new RuntimeException("Managed to obtain a system logger without permission");
+ }
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ System.out.println("Got expected exception for localized system logger: " + acx);
+ boolean old = allowControl.get().get();
+ allowControl.get().set(true);
+ try {
+ sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class);
+ loggerDescMap.put(sysLogger2, "provider.getLocalizedSystemLogger(\"foo\", loggerBundle)");
+ } finally {
+ allowControl.get().set(old);
+ }
+ }
+ if (appLogger2 == sysLogger2) {
+ throw new RuntimeException("identical loggers");
+ }
+ if (appLogger2 == appLogger1) {
+ throw new RuntimeException("identical loggers");
+ }
+ if (sysLogger2 == sysLogger1) {
+ throw new RuntimeException("identical loggers");
+ }
+
+
+ testLogger(provider, loggerDescMap, "foo", null, appLogger1, appSink);
+ testLogger(provider, loggerDescMap, "foo", null, sysLogger1, sysSink);
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, appLogger2, appSink);
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, sysLogger2, sysSink);
+
+
+ Logger appLogger3 = System.getLogger("foo");
+ loggerDescMap.put(appLogger3, "System.getLogger(\"foo\")");
+
+ testLogger(provider, loggerDescMap, "foo", null, appLogger3, appSink);
+
+ Logger appLogger4 =
+ System.getLogger("foo", loggerBundle);
+ loggerDescMap.put(appLogger4, "System.getLogger(\"foo\", loggerBundle)");
+
+ if (appLogger4 == appLogger1) {
+ throw new RuntimeException("identical loggers");
+ }
+
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, appLogger4, appSink);
+
+ Logger sysLogger3 = accessSystemLogger.getLogger("foo");
+ loggerDescMap.put(sysLogger3, "AccessSystemLogger.getLogger(\"foo\")");
+
+ testLogger(provider, loggerDescMap, "foo", null, sysLogger3, sysSink);
+
+ Logger sysLogger4 =
+ accessSystemLogger.getLogger("foo", loggerBundle);
+ loggerDescMap.put(appLogger4, "AccessSystemLogger.getLogger(\"foo\", loggerBundle)");
+
+ if (sysLogger4 == sysLogger1) {
+ throw new RuntimeException("identical loggers");
+ }
+
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, sysLogger4, sysSink);
+
+ }
+
+ public static class Foo {
+
+ }
+
+ static void verbose(String msg) {
+ if (VERBOSE) {
+ System.out.println(msg);
+ }
+ }
+
+ static void setLevel(java.util.logging.Logger sink, java.util.logging.Level loggerLevel) {
+ boolean before = allowAll.get().get();
+ try {
+ allowAll.get().set(true);
+ sink.setLevel(loggerLevel);
+ } finally {
+ allowAll.get().set(before);
+ }
+ }
+
+
+ // Calls the 8 methods defined on Logger and verify the
+ // parameters received by the underlying Logger Impl
+ // logger.
+ private static void testLogger(LoggerFinder provider,
+ Map<Logger, String> loggerDescMap,
+ String name,
+ ResourceBundle loggerBundle,
+ Logger logger,
+ java.util.logging.Logger sink) {
+
+ System.out.println("Testing " + loggerDescMap.get(logger) + " [" + logger + "]");
+ final java.util.logging.Level OFF = java.util.logging.Level.OFF;
+
+ Foo foo = new Foo();
+ String fooMsg = foo.toString();
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (Level messageLevel : Level.values()) {
+ java.util.logging.Level julLevel = mapToJul(messageLevel);
+ String desc = "logger.log(messageLevel, foo): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ julLevel.intValue() >= loggerLevel.intValue(),
+ name, julLevel, (ResourceBundle)null,
+ fooMsg, (Throwable)null, (Object[])null);
+ logger.log(messageLevel, foo);
+ if (loggerLevel == OFF || julLevel.intValue() < loggerLevel.intValue()) {
+ if (eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ String msg = "blah";
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (Level messageLevel : Level.values()) {
+ java.util.logging.Level julLevel = mapToJul(messageLevel);
+ String desc = "logger.log(messageLevel, \"blah\"): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ julLevel.intValue() >= loggerLevel.intValue(),
+ name, julLevel, loggerBundle,
+ msg, (Throwable)null, (Object[])null);
+ logger.log(messageLevel, msg);
+ if (loggerLevel == OFF || julLevel.intValue() < loggerLevel.intValue()) {
+ if (eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ Supplier<String> fooSupplier = new Supplier<String>() {
+ @Override
+ public String get() {
+ return this.toString();
+ }
+ };
+
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (Level messageLevel : Level.values()) {
+ java.util.logging.Level julLevel = mapToJul(messageLevel);
+ String desc = "logger.log(messageLevel, fooSupplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ julLevel.intValue() >= loggerLevel.intValue(),
+ name, julLevel, (ResourceBundle)null,
+ fooSupplier.get(),
+ (Throwable)null, (Object[])null);
+ logger.log(messageLevel, fooSupplier);
+ if (loggerLevel == OFF || julLevel.intValue() < loggerLevel.intValue()) {
+ if (eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ String format = "two params [{1} {2}]";
+ Object arg1 = foo;
+ Object arg2 = msg;
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (Level messageLevel : Level.values()) {
+ java.util.logging.Level julLevel = mapToJul(messageLevel);
+ String desc = "logger.log(messageLevel, format, params...): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ julLevel.intValue() >= loggerLevel.intValue(),
+ name, julLevel, loggerBundle,
+ format, (Throwable)null, new Object[] {arg1, arg2});
+ logger.log(messageLevel, format, arg1, arg2);
+ if (loggerLevel == OFF || julLevel.intValue() < loggerLevel.intValue()) {
+ if (eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ Throwable thrown = new Exception("OK: log me!");
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (Level messageLevel : Level.values()) {
+ java.util.logging.Level julLevel = mapToJul(messageLevel);
+ String desc = "logger.log(messageLevel, \"blah\", thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ julLevel.intValue() >= loggerLevel.intValue(),
+ name, julLevel, loggerBundle,
+ msg, thrown, (Object[]) null);
+ logger.log(messageLevel, msg, thrown);
+ if (loggerLevel == OFF || julLevel.intValue() < loggerLevel.intValue()) {
+ if (eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (Level messageLevel : Level.values()) {
+ java.util.logging.Level julLevel = mapToJul(messageLevel);
+ String desc = "logger.log(messageLevel, thrown, fooSupplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ julLevel.intValue() >= loggerLevel.intValue(),
+ name, julLevel, (ResourceBundle)null,
+ fooSupplier.get(),
+ (Throwable)thrown, (Object[])null);
+ logger.log(messageLevel, fooSupplier, thrown);
+ if (loggerLevel == OFF || julLevel.intValue() < loggerLevel.intValue()) {
+ if (eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ ResourceBundle bundle = ResourceBundle.getBundle(MyBundle.class.getName());
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (Level messageLevel : Level.values()) {
+ java.util.logging.Level julLevel = mapToJul(messageLevel);
+ String desc = "logger.log(messageLevel, bundle, format, params...): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ julLevel.intValue() >= loggerLevel.intValue(),
+ name, julLevel, bundle,
+ format, (Throwable)null, new Object[] {foo, msg});
+ logger.log(messageLevel, bundle, format, foo, msg);
+ if (loggerLevel == OFF || julLevel.intValue() < loggerLevel.intValue()) {
+ if (eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (Level messageLevel : Level.values()) {
+ java.util.logging.Level julLevel = mapToJul(messageLevel);
+ String desc = "logger.log(messageLevel, bundle, \"blah\", thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ julLevel.intValue() >= loggerLevel.intValue(),
+ name, julLevel, bundle,
+ msg, thrown, (Object[]) null);
+ logger.log(messageLevel, bundle, msg, thrown);
+ if (loggerLevel == OFF || julLevel.intValue() < loggerLevel.intValue()) {
+ if (eventQueue.poll() != null) {
+ throw new RuntimeException("unexpected event in queue for " + desc);
+ }
+ } else {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+ }
+ }
+ }
+
+ final static class PermissionsBuilder {
+ final Permissions perms;
+ public PermissionsBuilder() {
+ this(new Permissions());
+ }
+ public PermissionsBuilder(Permissions perms) {
+ this.perms = perms;
+ }
+ public PermissionsBuilder add(Permission p) {
+ perms.add(p);
+ return this;
+ }
+ public PermissionsBuilder addAll(PermissionCollection col) {
+ if (col != null) {
+ for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
+ perms.add(e.nextElement());
+ }
+ }
+ return this;
+ }
+ public Permissions toPermissions() {
+ final PermissionsBuilder builder = new PermissionsBuilder();
+ builder.addAll(perms);
+ return builder.perms;
+ }
+ }
+
+ public static class SimplePolicy extends Policy {
+
+ final Permissions permissions;
+ final Permissions withControlPermissions;
+ final Permissions allPermissions;
+ final ThreadLocal<AtomicBoolean> allowAll;
+ final ThreadLocal<AtomicBoolean> allowControl;
+ public SimplePolicy(ThreadLocal<AtomicBoolean> allowAll,
+ ThreadLocal<AtomicBoolean> allowControl) {
+ this.allowAll = allowAll;
+ this.allowControl = allowControl;
+ permissions = new Permissions();
+
+ withControlPermissions = new Permissions();
+ withControlPermissions.add(LOGGERFINDER_PERMISSION);
+
+ // these are used for configuring the test itself...
+ allPermissions = new Permissions();
+ allPermissions.add(new java.security.AllPermission());
+ }
+
+ @Override
+ public boolean implies(ProtectionDomain domain, Permission permission) {
+ if (allowAll.get().get()) return allPermissions.implies(permission);
+ if (allowControl.get().get()) return withControlPermissions.implies(permission);
+ return permissions.implies(permission);
+ }
+
+ @Override
+ public PermissionCollection getPermissions(CodeSource codesource) {
+ return new PermissionsBuilder().addAll(
+ allowAll.get().get() ? allPermissions :
+ allowControl.get().get()
+ ? withControlPermissions : permissions).toPermissions();
+ }
+
+ @Override
+ public PermissionCollection getPermissions(ProtectionDomain domain) {
+ return new PermissionsBuilder().addAll(
+ allowAll.get().get() ? allPermissions :
+ allowControl.get().get()
+ ? withControlPermissions : permissions).toPermissions();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/BaseDefaultLoggerFinderTest/AccessSystemLogger.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.IOException;
+import java.lang.System.Logger;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ResourceBundle;
+
+/**
+ *
+ * @author danielfuchs
+ */
+public final class AccessSystemLogger {
+
+ public AccessSystemLogger() {
+ this(check());
+ }
+
+ private AccessSystemLogger(Void unused) {
+ }
+
+ private static Void check() {
+ if (AccessSystemLogger.class.getClassLoader() != null) {
+ throw new RuntimeException("AccessSystemLogger should be loaded by the null classloader");
+ }
+ return null;
+ }
+
+ public Logger getLogger(String name) {
+ Logger logger = System.getLogger(name);
+ System.out.println("System.getLogger(\"" + name + "\"): " + logger);
+ return logger;
+ }
+
+ public Logger getLogger(String name, ResourceBundle bundle) {
+ Logger logger = System.getLogger(name, bundle);
+ System.out.println("System.getLogger(\"" + name + "\", bundle): " + logger);
+ return logger;
+ }
+
+ static final Class<?>[] toCopy = { AccessSystemLogger.class, CustomSystemClassLoader.class };
+
+ // copy AccessSystemLogger.class to ./boot
+ public static void main(String[] args) throws IOException {
+ Path testDir = Paths.get(System.getProperty("user.dir", "."));
+ Path bootDir = Paths.get(testDir.toString(), "boot");
+ Path classes = Paths.get(System.getProperty("test.classes", "build/classes"));
+ if (Files.notExists(bootDir)) {
+ Files.createDirectory(bootDir);
+ }
+ for (Class<?> c : toCopy) {
+ Path thisClass = Paths.get(classes.toString(),
+ c.getSimpleName()+".class");
+ Path dest = Paths.get(bootDir.toString(),
+ c.getSimpleName()+".class");
+ Files.copy(thisClass, dest, StandardCopyOption.REPLACE_EXISTING);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/BaseDefaultLoggerFinderTest/BaseDefaultLoggerFinderTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,768 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.UncheckedIOException;
+import java.security.AccessControlException;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.stream.Stream;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Supplier;
+import java.lang.System.LoggerFinder;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Locale;
+import java.util.concurrent.atomic.AtomicReference;
+import jdk.internal.logger.DefaultLoggerFinder;
+import jdk.internal.logger.SimpleConsoleLogger;
+import sun.util.logging.PlatformLogger;
+
+/**
+ * @test
+ * @bug 8140364
+ * @summary JDK implementation specific unit test for the base DefaultLoggerFinder.
+ * Tests the behavior of DefaultLoggerFinder and SimpleConsoleLogger
+ * implementation.
+ * @modules java.base/sun.util.logging
+ * java.base/jdk.internal.logger
+ * @build AccessSystemLogger BaseDefaultLoggerFinderTest CustomSystemClassLoader
+ * @run driver AccessSystemLogger
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseDefaultLoggerFinderTest NOSECURITY
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseDefaultLoggerFinderTest NOPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseDefaultLoggerFinderTest WITHPERMISSIONS
+ * @author danielfuchs
+ */
+public class BaseDefaultLoggerFinderTest {
+
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+ final static boolean VERBOSE = false;
+ static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+ static final ThreadLocal<AtomicBoolean> allowAccess = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+
+ final static AccessSystemLogger accessSystemLogger = new AccessSystemLogger();
+ static final Class<?>[] providerClass;
+ static {
+ try {
+ providerClass = new Class<?>[] {
+ ClassLoader.getSystemClassLoader().loadClass("BaseDefaultLoggerFinderTest$BaseLoggerFinder"),
+ };
+ } catch (ClassNotFoundException ex) {
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+ /**
+ * What our test provider needs to implement.
+ */
+ public static interface TestLoggerFinder {
+ public final static AtomicBoolean fails = new AtomicBoolean();
+ public final static AtomicReference<String> conf = new AtomicReference<>("");
+ public final static AtomicLong sequencer = new AtomicLong();
+
+
+ public Logger getLogger(String name, Class<?> caller);
+ public Logger getLocalizedLogger(String name, ResourceBundle bundle, Class<?> caller);
+ void setLevel(Logger logger, Level level, Class<?> caller);
+ void setLevel(Logger logger, PlatformLogger.Level level, Class<?> caller);
+ PlatformLogger.Bridge asPlatformLoggerBridge(Logger logger);
+ }
+
+ public static class BaseLoggerFinder extends DefaultLoggerFinder implements TestLoggerFinder {
+
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+ public BaseLoggerFinder() {
+ if (fails.get()) {
+ throw new RuntimeException("Simulate exception while loading provider");
+ }
+ }
+
+ @Override
+ public void setLevel(Logger logger, Level level, Class<?> caller) {
+ PrivilegedAction<Void> pa = () -> {
+ setLevel(logger, PlatformLogger.toPlatformLevel(level), caller);
+ return null;
+ };
+ AccessController.doPrivileged(pa);
+ }
+
+ @Override
+ public void setLevel(Logger logger, PlatformLogger.Level level, Class<?> caller) {
+ PrivilegedAction<Logger> pa = () -> demandLoggerFor(logger.getName(), caller);
+ Logger impl = AccessController.doPrivileged(pa);
+ SimpleConsoleLogger.class.cast(impl)
+ .getLoggerConfiguration()
+ .setPlatformLevel(level);
+ }
+
+ @Override
+ public PlatformLogger.Bridge asPlatformLoggerBridge(Logger logger) {
+ PrivilegedAction<PlatformLogger.Bridge> pa = () ->
+ PlatformLogger.Bridge.convert(logger);
+ return AccessController.doPrivileged(pa);
+ }
+
+ }
+
+ public static class MyBundle extends ResourceBundle {
+
+ final ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>();
+
+ @Override
+ protected Object handleGetObject(String key) {
+ if (key.contains(" (translated)")) {
+ throw new RuntimeException("Unexpected key: " + key);
+ }
+ return map.computeIfAbsent(key, k -> k.toUpperCase(Locale.ROOT) + " (translated)");
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ return Collections.enumeration(map.keySet());
+ }
+
+ }
+ public static class MyLoggerBundle extends MyBundle {
+
+ }
+
+ static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS};
+
+ static void setSecurityManager() {
+ if (System.getSecurityManager() == null) {
+ Policy.setPolicy(new SimplePolicy(allowControl, allowAccess));
+ System.setSecurityManager(new SecurityManager());
+ }
+ }
+
+ static TestLoggerFinder getLoggerFinder(Class<?> expectedClass) {
+ LoggerFinder provider = null;
+ try {
+ TestLoggerFinder.sequencer.incrementAndGet();
+ provider = LoggerFinder.getLoggerFinder();
+ } catch(AccessControlException a) {
+ throw a;
+ }
+ ErrorStream.errorStream.store();
+ System.out.println("*** Actual LoggerFinder class is: " + provider.getClass().getName());
+ expectedClass.cast(provider);
+ return TestLoggerFinder.class.cast(provider);
+ }
+
+
+ static class ErrorStream extends PrintStream {
+
+ static AtomicBoolean forward = new AtomicBoolean();
+ ByteArrayOutputStream out;
+ String saved = "";
+ public ErrorStream(ByteArrayOutputStream out) {
+ super(out);
+ this.out = out;
+ }
+
+ @Override
+ public void write(int b) {
+ super.write(b);
+ if (forward.get()) err.write(b);
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ super.write(b);
+ if (forward.get()) err.write(b);
+ }
+
+ @Override
+ public void write(byte[] buf, int off, int len) {
+ super.write(buf, off, len);
+ if (forward.get()) err.write(buf, off, len);
+ }
+
+ public String peek() {
+ flush();
+ return out.toString();
+ }
+
+ public String drain() {
+ flush();
+ String res = out.toString();
+ out.reset();
+ return res;
+ }
+
+ public void store() {
+ flush();
+ saved = out.toString();
+ out.reset();
+ }
+
+ public void restore() {
+ out.reset();
+ try {
+ out.write(saved.getBytes());
+ } catch(IOException io) {
+ throw new UncheckedIOException(io);
+ }
+ }
+
+ static final PrintStream err = System.err;
+ static final ErrorStream errorStream = new ErrorStream(new ByteArrayOutputStream());
+ }
+
+ private static StringBuilder appendProperty(StringBuilder b, String name) {
+ String value = System.getProperty(name);
+ if (value == null) return b;
+ return b.append(name).append("=").append(value).append('\n');
+ }
+
+ public static void main(String[] args) {
+ if (args.length == 0) {
+ args = new String[] {
+ //"NOSECURITY",
+ "NOPERMISSIONS",
+ "WITHPERMISSIONS"
+ };
+ }
+ Locale.setDefault(Locale.ENGLISH);
+ System.setErr(ErrorStream.errorStream);
+ //System.setProperty("jdk.logger.finder.error", "ERROR");
+ //System.setProperty("jdk.logger.finder.singleton", "true");
+ //System.setProperty("test.fails", "true");
+ TestLoggerFinder.fails.set(Boolean.getBoolean("test.fails"));
+ StringBuilder c = new StringBuilder();
+ appendProperty(c, "jdk.logger.packages");
+ appendProperty(c, "jdk.logger.finder.error");
+ appendProperty(c, "jdk.logger.finder.singleton");
+ appendProperty(c, "test.fails");
+ TestLoggerFinder.conf.set(c.toString());
+ try {
+ test(args);
+ } finally {
+ try {
+ System.setErr(ErrorStream.err);
+ } catch (Error | RuntimeException x) {
+ x.printStackTrace(ErrorStream.err);
+ }
+ }
+ }
+
+
+ public static void test(String[] args) {
+
+ final Class<?> expectedClass = jdk.internal.logger.DefaultLoggerFinder.class;
+
+ System.out.println("Declared provider class: " + providerClass[0]
+ + "[" + providerClass[0].getClassLoader() + "]");
+
+ Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> {
+ TestLoggerFinder provider;
+ ErrorStream.errorStream.restore();
+ switch (testCase) {
+ case NOSECURITY:
+ System.out.println("\n*** Without Security Manager\n");
+ System.out.println(TestLoggerFinder.conf.get());
+ provider = getLoggerFinder(expectedClass);
+ if (!provider.getClass().getName().equals("BaseDefaultLoggerFinderTest$BaseLoggerFinder")) {
+ throw new RuntimeException("Unexpected provider: " + provider.getClass().getName());
+ }
+ test(provider, true);
+ System.out.println("Tetscase count: " + TestLoggerFinder.sequencer.get());
+ break;
+ case NOPERMISSIONS:
+ System.out.println("\n*** With Security Manager, without permissions\n");
+ System.out.println(TestLoggerFinder.conf.get());
+ setSecurityManager();
+ try {
+ provider = getLoggerFinder(expectedClass);
+ throw new RuntimeException("Expected exception not raised");
+ } catch (AccessControlException x) {
+ if (!LOGGERFINDER_PERMISSION.equals(x.getPermission())) {
+ throw new RuntimeException("Unexpected permission check", x);
+ }
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = getLoggerFinder(expectedClass);
+ if (!provider.getClass().getName().equals("BaseDefaultLoggerFinderTest$BaseLoggerFinder")) {
+ throw new RuntimeException("Unexpected provider: " + provider.getClass().getName());
+ }
+ } finally {
+ allowControl.get().set(control);
+ }
+ }
+ test(provider, false);
+ System.out.println("Tetscase count: " + TestLoggerFinder.sequencer.get());
+ break;
+ case WITHPERMISSIONS:
+ System.out.println("\n*** With Security Manager, with control permission\n");
+ System.out.println(TestLoggerFinder.conf.get());
+ setSecurityManager();
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = getLoggerFinder(expectedClass);
+ if (!provider.getClass().getName().equals("BaseDefaultLoggerFinderTest$BaseLoggerFinder")) {
+ throw new RuntimeException("Unexpected provider: " + provider.getClass().getName());
+ }
+ test(provider, true);
+ } finally {
+ allowControl.get().set(control);
+ }
+ break;
+ default:
+ throw new RuntimeException("Unknown test case: " + testCase);
+ }
+ });
+ System.out.println("\nPASSED: Tested " + TestLoggerFinder.sequencer.get() + " cases.");
+ }
+
+ public static void test(TestLoggerFinder provider, boolean hasRequiredPermissions) {
+
+ ResourceBundle loggerBundle = ResourceBundle.getBundle(MyLoggerBundle.class.getName());
+ final Map<Logger, String> loggerDescMap = new HashMap<>();
+
+ System.Logger sysLogger = accessSystemLogger.getLogger("foo");
+ loggerDescMap.put(sysLogger, "accessSystemLogger.getLogger(\"foo\")");
+ System.Logger localizedSysLogger = accessSystemLogger.getLogger("fox", loggerBundle);
+ loggerDescMap.put(localizedSysLogger, "accessSystemLogger.getLogger(\"fox\", loggerBundle)");
+ System.Logger appLogger = System.getLogger("bar");
+ loggerDescMap.put(appLogger,"System.getLogger(\"bar\")");
+ System.Logger localizedAppLogger = System.getLogger("baz", loggerBundle);
+ loggerDescMap.put(localizedAppLogger,"System.getLogger(\"baz\", loggerBundle)");
+
+ testLogger(provider, loggerDescMap, "foo", null, sysLogger, accessSystemLogger.getClass());
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, localizedSysLogger, accessSystemLogger.getClass());
+ testLogger(provider, loggerDescMap, "foo", null, appLogger, BaseDefaultLoggerFinderTest.class);
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, localizedAppLogger, BaseDefaultLoggerFinderTest.class);
+ }
+
+ public static class Foo {
+
+ }
+
+ static void verbose(String msg) {
+ if (VERBOSE) {
+ System.out.println(msg);
+ }
+ }
+
+ // Calls the 8 methods defined on Logger and verify the
+ // parameters received by the underlying TestProvider.LoggerImpl
+ // logger.
+ private static void testLogger(TestLoggerFinder provider,
+ Map<Logger, String> loggerDescMap,
+ String name,
+ ResourceBundle loggerBundle,
+ Logger logger,
+ Class<?> caller) {
+
+ System.out.println("Testing " + loggerDescMap.get(logger) + " [" + logger +"]");
+ AtomicLong sequencer = TestLoggerFinder.sequencer;
+
+ Foo foo = new Foo();
+ String fooMsg = foo.toString();
+ for (Level loggerLevel : Level.values()) {
+ provider.setLevel(logger, loggerLevel, caller);
+ for (Level messageLevel : Level.values()) {
+ ErrorStream.errorStream.drain();
+ String desc = "logger.log(messageLevel, foo): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ sequencer.incrementAndGet();
+ logger.log(messageLevel, foo);
+ if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (!ErrorStream.errorStream.peek().isEmpty()) {
+ throw new RuntimeException("unexpected event in queue for "
+ + desc +": " + "\n\t" + ErrorStream.errorStream.drain());
+ }
+ } else {
+ String logged = ErrorStream.errorStream.drain();
+ if (!logged.contains("BaseDefaultLoggerFinderTest testLogger")
+ || !logged.contains(messageLevel.getName() + ": " + fooMsg)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected:" + "\n<<<<\n"
+ + "[date] BaseDefaultLoggerFinderTest testLogger\n"
+ + messageLevel.getName() + " " + fooMsg
+ + "\n>>>>"
+ + "\n\t actual:"
+ + "\n<<<<\n" + logged + ">>>>\n");
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n<<<<\n" + logged + ">>>>\n");
+ }
+ }
+ }
+ }
+
+ String msg = "blah";
+ for (Level loggerLevel : Level.values()) {
+ provider.setLevel(logger, loggerLevel, caller);
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, \"blah\"): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ sequencer.incrementAndGet();
+ logger.log(messageLevel, msg);
+ if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (!ErrorStream.errorStream.peek().isEmpty()) {
+ throw new RuntimeException("unexpected event in queue for "
+ + desc +": " + "\n\t" + ErrorStream.errorStream.drain());
+ }
+ } else {
+ String logged = ErrorStream.errorStream.drain();
+ String msgText = loggerBundle == null ? msg : loggerBundle.getString(msg);
+ if (!logged.contains("BaseDefaultLoggerFinderTest testLogger")
+ || !logged.contains(messageLevel.getName() + ": " + msgText)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected:" + "\n<<<<\n"
+ + "[date] BaseDefaultLoggerFinderTest testLogger\n"
+ + messageLevel.getName() + " " + msgText
+ + "\n>>>>"
+ + "\n\t actual:"
+ + "\n<<<<\n" + logged + ">>>>\n");
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n<<<<\n" + logged + ">>>>\n");
+ }
+ }
+ }
+ }
+
+ Supplier<String> fooSupplier = new Supplier<String>() {
+ @Override
+ public String get() {
+ return this.toString();
+ }
+ };
+
+ for (Level loggerLevel : Level.values()) {
+ provider.setLevel(logger, loggerLevel, caller);
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, fooSupplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ sequencer.incrementAndGet();
+ logger.log(messageLevel, fooSupplier);
+ if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (!ErrorStream.errorStream.peek().isEmpty()) {
+ throw new RuntimeException("unexpected event in queue for "
+ + desc +": " + "\n\t" + ErrorStream.errorStream.drain());
+ }
+ } else {
+ String logged = ErrorStream.errorStream.drain();
+ if (!logged.contains("BaseDefaultLoggerFinderTest testLogger")
+ || !logged.contains(messageLevel.getName() + ": " + fooSupplier.get())) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected:" + "\n<<<<\n"
+ + "[date] BaseDefaultLoggerFinderTest testLogger\n"
+ + messageLevel.getName() + " " + fooSupplier.get()
+ + "\n>>>>"
+ + "\n\t actual:"
+ + "\n<<<<\n" + logged + ">>>>\n");
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n<<<<\n" + logged + ">>>>\n");
+ }
+ }
+ }
+ }
+
+
+ String format = "two params [{1} {2}]";
+ Object arg1 = foo;
+ Object arg2 = msg;
+ for (Level loggerLevel : Level.values()) {
+ provider.setLevel(logger, loggerLevel, caller);
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, format, params...): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ sequencer.incrementAndGet();
+ logger.log(messageLevel, format, foo, msg);
+ if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (!ErrorStream.errorStream.peek().isEmpty()) {
+ throw new RuntimeException("unexpected event in queue for "
+ + desc +": " + "\n\t" + ErrorStream.errorStream.drain());
+ }
+ } else {
+ String logged = ErrorStream.errorStream.drain();
+ String msgFormat = loggerBundle == null ? format : loggerBundle.getString(format);
+ String text = java.text.MessageFormat.format(msgFormat, foo, msg);
+ if (!logged.contains("BaseDefaultLoggerFinderTest testLogger")
+ || !logged.contains(messageLevel.getName() + ": " + text)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected:" + "\n<<<<\n"
+ + "[date] BaseDefaultLoggerFinderTest testLogger\n"
+ + messageLevel.getName() + " " + text
+ + "\n>>>>"
+ + "\n\t actual:"
+ + "\n<<<<\n" + logged + ">>>>\n");
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n<<<<\n" + logged + ">>>>\n");
+ }
+ }
+ }
+ }
+
+ Throwable thrown = new Exception("OK: log me!");
+ for (Level loggerLevel : Level.values()) {
+ provider.setLevel(logger, loggerLevel, caller);
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, \"blah\", thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ sequencer.incrementAndGet();
+ logger.log(messageLevel, msg, thrown);
+ if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (!ErrorStream.errorStream.peek().isEmpty()) {
+ throw new RuntimeException("unexpected event in queue for "
+ + desc +": " + "\n\t" + ErrorStream.errorStream.drain());
+ }
+ } else {
+ String logged = ErrorStream.errorStream.drain();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ thrown.printStackTrace(new PrintStream(baos));
+ String text = baos.toString();
+ String msgText = loggerBundle == null ? msg : loggerBundle.getString(msg);
+ if (!logged.contains("BaseDefaultLoggerFinderTest testLogger")
+ || !logged.contains(messageLevel.getName() + ": " + msgText)
+ || !logged.contains(text)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected:" + "\n<<<<\n"
+ + "[date] BaseDefaultLoggerFinderTest testLogger\n"
+ + messageLevel.getName() + " " + msgText +"\n"
+ + text
+ + ">>>>"
+ + "\n\t actual:"
+ + "\n<<<<\n" + logged + ">>>>\n");
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n<<<<\n" + logged + ">>>>\n");
+ }
+ }
+ }
+ }
+
+
+ for (Level loggerLevel : Level.values()) {
+ provider.setLevel(logger, loggerLevel, caller);
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, thrown, fooSupplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ sequencer.incrementAndGet();
+ logger.log(messageLevel, fooSupplier, thrown);
+ if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (!ErrorStream.errorStream.peek().isEmpty()) {
+ throw new RuntimeException("unexpected event in queue for "
+ + desc +": " + "\n\t" + ErrorStream.errorStream.drain());
+ }
+ } else {
+ String logged = ErrorStream.errorStream.drain();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ thrown.printStackTrace(new PrintStream(baos));
+ String text = baos.toString();
+ if (!logged.contains("BaseDefaultLoggerFinderTest testLogger")
+ || !logged.contains(messageLevel.getName() + ": " + fooSupplier.get())
+ || !logged.contains(text)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected:" + "\n<<<<\n"
+ + "[date] BaseDefaultLoggerFinderTest testLogger\n"
+ + messageLevel.getName() + " " + fooSupplier.get() +"\n"
+ + text
+ + ">>>>"
+ + "\n\t actual:"
+ + "\n<<<<\n" + logged + ">>>>\n");
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n<<<<\n" + logged + ">>>>\n");
+ }
+ }
+ }
+ }
+
+ ResourceBundle bundle = ResourceBundle.getBundle(MyBundle.class.getName());
+ for (Level loggerLevel : Level.values()) {
+ provider.setLevel(logger, loggerLevel, caller);
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, bundle, format, params...): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ sequencer.incrementAndGet();
+ logger.log(messageLevel, bundle, format, foo, msg);
+ if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (!ErrorStream.errorStream.peek().isEmpty()) {
+ throw new RuntimeException("unexpected event in queue for "
+ + desc +": " + "\n\t" + ErrorStream.errorStream.drain());
+ }
+ } else {
+ String logged = ErrorStream.errorStream.drain();
+ String text = java.text.MessageFormat.format(bundle.getString(format), foo, msg);
+ if (!logged.contains("BaseDefaultLoggerFinderTest testLogger")
+ || !logged.contains(messageLevel.getName() + ": " + text)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected:" + "\n<<<<\n"
+ + "[date] BaseDefaultLoggerFinderTest testLogger\n"
+ + messageLevel.getName() + " " + text
+ + "\n>>>>"
+ + "\n\t actual:"
+ + "\n<<<<\n" + logged + ">>>>\n");
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n<<<<\n" + logged + ">>>>\n");
+ }
+ }
+ }
+ }
+
+ for (Level loggerLevel : Level.values()) {
+ provider.setLevel(logger, loggerLevel, caller);
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, bundle, \"blah\", thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ sequencer.incrementAndGet();
+ logger.log(messageLevel, bundle, msg, thrown);
+ if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (!ErrorStream.errorStream.peek().isEmpty()) {
+ throw new RuntimeException("unexpected event in queue for "
+ + desc +": " + "\n\t" + ErrorStream.errorStream.drain());
+ }
+ } else {
+ String logged = ErrorStream.errorStream.drain();
+ String textMsg = bundle.getString(msg);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ thrown.printStackTrace(new PrintStream(baos));
+ String text = baos.toString();
+ if (!logged.contains("BaseDefaultLoggerFinderTest testLogger")
+ || !logged.contains(messageLevel.getName() + ": " + textMsg)
+ || !logged.contains(text)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected:" + "\n<<<<\n"
+ + "[date] BaseDefaultLoggerFinderTest testLogger\n"
+ + messageLevel.getName() + " " + textMsg +"\n"
+ + text
+ + ">>>>"
+ + "\n\t actual:"
+ + "\n<<<<\n" + logged + ">>>>\n");
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n<<<<\n" + logged + ">>>>\n");
+ }
+ }
+ }
+ }
+
+ }
+
+ final static class PermissionsBuilder {
+ final Permissions perms;
+ public PermissionsBuilder() {
+ this(new Permissions());
+ }
+ public PermissionsBuilder(Permissions perms) {
+ this.perms = perms;
+ }
+ public PermissionsBuilder add(Permission p) {
+ perms.add(p);
+ return this;
+ }
+ public PermissionsBuilder addAll(PermissionCollection col) {
+ if (col != null) {
+ for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
+ perms.add(e.nextElement());
+ }
+ }
+ return this;
+ }
+ public Permissions toPermissions() {
+ final PermissionsBuilder builder = new PermissionsBuilder();
+ builder.addAll(perms);
+ return builder.perms;
+ }
+ }
+
+ public static class SimplePolicy extends Policy {
+ final static RuntimePermission CONTROL = LOGGERFINDER_PERMISSION;
+ final static RuntimePermission ACCESS = new RuntimePermission("accessClassInPackage.jdk.internal.logger");
+
+ final Permissions permissions;
+ final ThreadLocal<AtomicBoolean> allowControl;
+ final ThreadLocal<AtomicBoolean> allowAccess;
+ public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl, ThreadLocal<AtomicBoolean> allowAccess) {
+ this.allowControl = allowControl;
+ this.allowAccess = allowAccess;
+ permissions = new Permissions();
+ permissions.add(new RuntimePermission("setIO"));
+ }
+
+ Permissions getPermissions() {
+ if (allowControl.get().get() || allowAccess.get().get()) {
+ PermissionsBuilder builder = new PermissionsBuilder()
+ .addAll(permissions);
+ if (allowControl.get().get()) {
+ builder.add(CONTROL);
+ }
+ if (allowAccess.get().get()) {
+ builder.add(ACCESS);
+ }
+ return builder.toPermissions();
+ }
+ return permissions;
+ }
+
+ @Override
+ public boolean implies(ProtectionDomain domain, Permission permission) {
+ return getPermissions().implies(permission);
+ }
+
+ @Override
+ public PermissionCollection getPermissions(CodeSource codesource) {
+ return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
+ }
+
+ @Override
+ public PermissionCollection getPermissions(ProtectionDomain domain) {
+ return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/BaseDefaultLoggerFinderTest/CustomSystemClassLoader.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.security.AllPermission;
+import java.security.Permissions;
+import java.security.ProtectionDomain;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * A custom ClassLoader to load the concrete LoggerFinder class
+ * with all permissions. The CustomSystemClassLoader class must be
+ * in the BCL, otherwise when system classes - such as
+ * ZoneDateTime try to load their resource bundle a MissingResourceBundle
+ * caused by a SecurityException may be thrown, as the CustomSystemClassLoader
+ * code base will be found in the stack called by doPrivileged.
+ *
+ * @author danielfuchs
+ */
+public class CustomSystemClassLoader extends ClassLoader {
+
+
+ final List<String> finderClassNames =
+ Arrays.asList("BaseDefaultLoggerFinderTest$BaseLoggerFinder");
+ final Map<String, Class<?>> finderClasses = new HashMap<>();
+ Class<?> testLoggerFinderClass;
+
+ public CustomSystemClassLoader() {
+ super();
+ }
+ public CustomSystemClassLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ private Class<?> defineFinderClass(String name)
+ throws ClassNotFoundException {
+ final Object obj = getClassLoadingLock(name);
+ synchronized(obj) {
+ if (finderClasses.get(name) != null) return finderClasses.get(name);
+ if (testLoggerFinderClass == null) {
+ // Hack: we load testLoggerFinderClass to get its code source.
+ // we can't use this.getClass() since we are in the boot.
+ testLoggerFinderClass = super.loadClass("BaseDefaultLoggerFinderTest$TestLoggerFinder");
+ }
+ URL url = testLoggerFinderClass.getProtectionDomain().getCodeSource().getLocation();
+ File file = new File(url.getPath(), name+".class");
+ if (file.canRead()) {
+ try {
+ byte[] b = Files.readAllBytes(file.toPath());
+ Permissions perms = new Permissions();
+ perms.add(new AllPermission());
+ Class<?> finderClass = defineClass(
+ name, b, 0, b.length, new ProtectionDomain(
+ this.getClass().getProtectionDomain().getCodeSource(),
+ perms));
+ System.out.println("Loaded " + name);
+ finderClasses.put(name, finderClass);
+ return finderClass;
+ } catch (Throwable ex) {
+ ex.printStackTrace();
+ throw new ClassNotFoundException(name, ex);
+ }
+ } else {
+ throw new ClassNotFoundException(name,
+ new IOException(file.toPath() + ": can't read"));
+ }
+ }
+ }
+
+ @Override
+ public synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ if (finderClassNames.contains(name)) {
+ Class<?> c = defineFinderClass(name);
+ if (resolve) {
+ resolveClass(c);
+ }
+ return c;
+ }
+ return super.loadClass(name, resolve);
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ if (finderClassNames.contains(name)) {
+ return defineFinderClass(name);
+ }
+ return super.findClass(name);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/BaseDefaultLoggerFinderTest/META-INF/services/java.lang.System$LoggerFinder Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,1 @@
+BaseDefaultLoggerFinderTest$BaseLoggerFinder
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/BaseLoggerBridgeTest/BaseLoggerBridgeTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,1058 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.ResourceBundle;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Supplier;
+import sun.util.logging.PlatformLogger;
+import java.lang.System.LoggerFinder;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.util.stream.Stream;
+
+/**
+ * @test
+ * @bug 8140364
+ * @summary JDK implementation specific unit test for JDK internal artifacts.
+ * Tests a naive implementation of System.Logger, and in particular
+ * the default mapping provided by PlatformLogger.Bridge.
+ * @modules java.base/sun.util.logging java.base/jdk.internal.logger
+ * @build CustomSystemClassLoader BaseLoggerBridgeTest
+ * @run main/othervm -Djava.system.class.loader=CustomSystemClassLoader BaseLoggerBridgeTest NOSECURITY
+ * @run main/othervm -Djava.system.class.loader=CustomSystemClassLoader BaseLoggerBridgeTest NOPERMISSIONS
+ * @run main/othervm -Djava.system.class.loader=CustomSystemClassLoader BaseLoggerBridgeTest WITHPERMISSIONS
+ * @author danielfuchs
+ */
+public class BaseLoggerBridgeTest {
+
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+ final static AtomicLong sequencer = new AtomicLong();
+ final static boolean VERBOSE = false;
+ // whether the implementation of Logger try to do a best
+ // effort for logp... Our base logger finder stub doesn't
+ // support logp, and thus the logp() implementation comes from
+ // LoggerWrapper - which does a best effort.
+ static final boolean BEST_EFFORT_FOR_LOGP = true;
+ static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+ static final ThreadLocal<AtomicBoolean> allowAccess = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+ static final ThreadLocal<AtomicBoolean> allowAll = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+
+ static final Class<?> providerClass;
+ static {
+ try {
+ providerClass = ClassLoader.getSystemClassLoader().loadClass("BaseLoggerBridgeTest$BaseLoggerFinder");
+ } catch (ClassNotFoundException ex) {
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+ static final sun.util.logging.PlatformLogger.Level[] julLevels = {
+ sun.util.logging.PlatformLogger.Level.ALL,
+ sun.util.logging.PlatformLogger.Level.FINEST,
+ sun.util.logging.PlatformLogger.Level.FINER,
+ sun.util.logging.PlatformLogger.Level.FINE,
+ sun.util.logging.PlatformLogger.Level.CONFIG,
+ sun.util.logging.PlatformLogger.Level.INFO,
+ sun.util.logging.PlatformLogger.Level.WARNING,
+ sun.util.logging.PlatformLogger.Level.SEVERE,
+ sun.util.logging.PlatformLogger.Level.OFF,
+ };
+
+ static final Level[] mappedLevels = {
+ Level.ALL, // ALL
+ Level.TRACE, // FINEST
+ Level.TRACE, // FINER
+ Level.DEBUG, // FINE
+ Level.DEBUG, // CONFIG
+ Level.INFO, // INFO
+ Level.WARNING, // WARNING
+ Level.ERROR, // SEVERE
+ Level.OFF, // OFF
+ };
+
+ final static Map<sun.util.logging.PlatformLogger.Level, Level> julToSpiMap;
+ static {
+ Map<sun.util.logging.PlatformLogger.Level, Level> map = new HashMap<>();
+ if (mappedLevels.length != julLevels.length) {
+ throw new ExceptionInInitializerError("Array lengths differ"
+ + "\n\tjulLevels=" + Arrays.deepToString(julLevels)
+ + "\n\tmappedLevels=" + Arrays.deepToString(mappedLevels));
+ }
+ for (int i=0; i<julLevels.length; i++) {
+ map.put(julLevels[i], mappedLevels[i]);
+ }
+ julToSpiMap = Collections.unmodifiableMap(map);
+ }
+
+ public static class MyBundle extends ResourceBundle {
+
+ final ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>();
+
+ @Override
+ protected Object handleGetObject(String key) {
+ if (key.contains(" (translated)")) {
+ throw new RuntimeException("Unexpected key: " + key);
+ }
+ return map.computeIfAbsent(key, k -> k + " (translated)");
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ return Collections.enumeration(map.keySet());
+ }
+
+ }
+ public static class MyLoggerBundle extends MyBundle {
+
+ }
+
+ public static interface TestLoggerFinder {
+ final ConcurrentHashMap<String, LoggerImpl> system = new ConcurrentHashMap<>();
+ final ConcurrentHashMap<String, LoggerImpl> user = new ConcurrentHashMap<>();
+ public Queue<LogEvent> eventQueue = new ArrayBlockingQueue<>(128);
+
+ public static final class LogEvent implements Cloneable {
+
+ public LogEvent() {
+ this(sequencer.getAndIncrement());
+ }
+
+ LogEvent(long sequenceNumber) {
+ this.sequenceNumber = sequenceNumber;
+ }
+
+ boolean callSupplier = false;
+ long sequenceNumber;
+ boolean isLoggable;
+ String loggerName;
+ Level level;
+ ResourceBundle bundle;
+ Throwable thrown;
+ Object[] args;
+ Supplier<String> supplier;
+ String msg;
+
+ Object[] toArray(boolean callSupplier) {
+ return new Object[] {
+ sequenceNumber,
+ isLoggable,
+ loggerName,
+ level,
+ bundle,
+ thrown,
+ args,
+ callSupplier && supplier != null ? supplier.get() : supplier,
+ msg,
+ };
+ }
+
+ boolean callSupplier(Object obj) {
+ return callSupplier || ((LogEvent)obj).callSupplier;
+ }
+
+ @Override
+ public String toString() {
+ return Arrays.deepToString(toArray(false));
+ }
+
+
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof LogEvent
+ && Objects.deepEquals(toArray(callSupplier(obj)), ((LogEvent)obj).toArray(callSupplier(obj)));
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(toArray(true));
+ }
+
+ public LogEvent cloneWith(long sequenceNumber)
+ throws CloneNotSupportedException {
+ LogEvent cloned = (LogEvent)super.clone();
+ cloned.sequenceNumber = sequenceNumber;
+ return cloned;
+ }
+
+ public static LogEvent of(boolean isLoggable, String name,
+ Level level, ResourceBundle bundle,
+ String key, Throwable thrown) {
+ LogEvent evt = new LogEvent();
+ evt.isLoggable = isLoggable;
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = null;
+ evt.bundle = bundle;
+ evt.thrown = thrown;
+ evt.supplier = null;
+ evt.msg = key;
+ return evt;
+ }
+
+ public static LogEvent of(boolean isLoggable, String name,
+ Level level, Throwable thrown, Supplier<String> supplier) {
+ LogEvent evt = new LogEvent();
+ evt.isLoggable = isLoggable;
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = null;
+ evt.bundle = null;
+ evt.thrown = thrown;
+ evt.supplier = supplier;
+ evt.msg = null;
+ return evt;
+ }
+
+ public static LogEvent of(boolean isLoggable, String name,
+ Level level, ResourceBundle bundle,
+ String key, Object... params) {
+ LogEvent evt = new LogEvent();
+ evt.isLoggable = isLoggable;
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = params;
+ evt.bundle = bundle;
+ evt.thrown = null;
+ evt.supplier = null;
+ evt.msg = key;
+ return evt;
+ }
+
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ Level level, ResourceBundle bundle,
+ String key, Supplier<String> supplier,
+ Throwable thrown, Object... params) {
+ LogEvent evt = new LogEvent(sequenceNumber);
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = params;
+ evt.bundle = bundle;
+ evt.thrown = thrown;
+ evt.supplier = supplier;
+ evt.msg = key;
+ evt.isLoggable = isLoggable;
+ return evt;
+ }
+
+ public static LogEvent ofp(boolean callSupplier, LogEvent evt) {
+ evt.callSupplier = callSupplier;
+ return evt;
+ }
+ }
+
+ public class LoggerImpl implements Logger {
+ private final String name;
+ private Level level = Level.INFO;
+
+ public LoggerImpl(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean isLoggable(Level level) {
+ return this.level != Level.OFF && this.level.getSeverity() <= level.getSeverity();
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle, String key, Throwable thrown) {
+ log(LogEvent.of(isLoggable(level), this.name, level, bundle, key, thrown));
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle, String format, Object... params) {
+ log(LogEvent.of(isLoggable(level), name, level, bundle, format, params));
+ }
+
+ void log(LogEvent event) {
+ eventQueue.add(event);
+ }
+
+ @Override
+ public void log(Level level, Supplier<String> msgSupplier) {
+ log(LogEvent.of(isLoggable(level), name, level, null, msgSupplier));
+ }
+
+ @Override
+ public void log(Level level, Supplier<String> msgSupplier, Throwable thrown) {
+ log(LogEvent.of(isLoggable(level), name, level, thrown, msgSupplier));
+ }
+
+
+
+ }
+
+ public Logger getLogger(String name, Class<?> caller);
+ public Logger getLocalizedLogger(String name, ResourceBundle bundle, Class<?> caller);
+ }
+
+ public static class BaseLoggerFinder extends LoggerFinder implements TestLoggerFinder {
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+ @Override
+ public Logger getLogger(String name, Class<?> caller) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGERFINDER_PERMISSION);
+ }
+ PrivilegedAction<ClassLoader> pa = () -> caller.getClassLoader();
+ ClassLoader callerLoader = AccessController.doPrivileged(pa);
+ if (callerLoader == null) {
+ return system.computeIfAbsent(name, (n) -> new LoggerImpl(n));
+ } else {
+ return user.computeIfAbsent(name, (n) -> new LoggerImpl(n));
+ }
+ }
+ }
+
+ static PlatformLogger.Bridge convert(Logger logger) {
+ boolean old = allowAll.get().get();
+ allowAccess.get().set(true);
+ try {
+ return PlatformLogger.Bridge.convert(logger);
+ } finally {
+ allowAccess.get().set(old);
+ }
+ }
+
+ static Logger getLogger(String name, Class<?> caller) {
+ boolean old = allowAll.get().get();
+ allowAccess.get().set(true);
+ try {
+ return jdk.internal.logger.LazyLoggers.getLogger(name, caller);
+ } finally {
+ allowAccess.get().set(old);
+ }
+ }
+
+ static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS};
+
+ static void setSecurityManager() {
+ if (System.getSecurityManager() == null) {
+ // Ugly test hack: preload the resources needed by String.format
+ // We need to do that before setting the security manager
+ // because our implementation of CustomSystemClassLoader
+ // doesn't have the required permission.
+ System.out.println(String.format("debug: %s", "Setting security manager"));
+ Policy.setPolicy(new SimplePolicy(allowControl, allowAccess, allowAll));
+ System.setSecurityManager(new SecurityManager());
+ }
+ }
+
+ public static void main(String[] args) {
+ if (args.length == 0)
+ args = new String[] {
+ "NOSECURITY",
+ "NOPERMISSIONS",
+ "WITHPERMISSIONS"
+ };
+
+
+ Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> {
+ TestLoggerFinder provider;
+ switch (testCase) {
+ case NOSECURITY:
+ System.out.println("\n*** Without Security Manager\n");
+ provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
+ test(provider, true);
+ System.out.println("Tetscase count: " + sequencer.get());
+ break;
+ case NOPERMISSIONS:
+ System.out.println("\n*** With Security Manager, without permissions\n");
+ setSecurityManager();
+ try {
+ provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
+ throw new RuntimeException("Expected exception not raised");
+ } catch (AccessControlException x) {
+ if (!LOGGERFINDER_PERMISSION.equals(x.getPermission())) {
+ throw new RuntimeException("Unexpected permission check", x);
+ }
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
+ } finally {
+ allowControl.get().set(control);
+ }
+ }
+ test(provider, false);
+ System.out.println("Tetscase count: " + sequencer.get());
+ break;
+ case WITHPERMISSIONS:
+ System.out.println("\n*** With Security Manager, with control permission\n");
+ setSecurityManager();
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
+ test(provider, true);
+ } finally {
+ allowControl.get().set(control);
+ }
+ break;
+ default:
+ throw new RuntimeException("Unknown test case: " + testCase);
+ }
+ });
+ System.out.println("\nPASSED: Tested " + sequencer.get() + " cases.");
+ }
+
+ public static void test(TestLoggerFinder provider, boolean hasRequiredPermissions) {
+
+ ResourceBundle loggerBundle = ResourceBundle.getBundle(MyLoggerBundle.class.getName());
+ final Map<Object, String> loggerDescMap = new HashMap<>();
+
+
+ TestLoggerFinder.LoggerImpl appSink = null;
+ try {
+ appSink = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", BaseLoggerBridgeTest.class));
+ if (!hasRequiredPermissions) {
+ throw new RuntimeException("Managed to obtain a system logger without permission");
+ }
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ System.out.println("Got expected exception for logger: " + acx);
+ boolean old = allowControl.get().get();
+ allowControl.get().set(true);
+ try {
+ appSink = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", BaseLoggerBridgeTest.class));
+ } finally {
+ allowControl.get().set(old);
+ }
+ }
+
+
+ TestLoggerFinder.LoggerImpl sysSink = null;
+ try {
+ sysSink = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class));
+ if (!hasRequiredPermissions) {
+ throw new RuntimeException("Managed to obtain a system logger without permission");
+ }
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ System.out.println("Got expected exception for system logger: " + acx);
+ }
+ if (hasRequiredPermissions && appSink == sysSink) {
+ throw new RuntimeException("identical loggers");
+ }
+
+ if (provider.system.contains(appSink)) {
+ throw new RuntimeException("app logger in system map");
+ }
+ if (!provider.user.contains(appSink)) {
+ throw new RuntimeException("app logger not in appplication map");
+ }
+ if (hasRequiredPermissions && provider.user.contains(sysSink)) {
+ throw new RuntimeException("sys logger in appplication map");
+ }
+ if (hasRequiredPermissions && !provider.system.contains(sysSink)) {
+ throw new RuntimeException("sys logger not in system map");
+ }
+
+ Logger appLogger1 = System.getLogger("foo");
+ loggerDescMap.put(appLogger1, "System.getLogger(\"foo\")");
+ PlatformLogger.Bridge bridge = convert(appLogger1);
+ loggerDescMap.putIfAbsent(bridge, "PlatformLogger.Bridge.convert(System.getLogger(\"foo\"))");
+ testLogger(provider, loggerDescMap, "foo", null, bridge, appSink);
+
+ Logger sysLogger1 = null;
+ try {
+ sysLogger1 = getLogger("foo", Thread.class);
+ loggerDescMap.put(sysLogger1,
+ "jdk.internal.logger.LazyLoggers.getLogger(\"foo\", Thread.class)");
+
+ if (!hasRequiredPermissions) {
+ // check that the provider would have thrown an exception
+ provider.getLogger("foo", Thread.class);
+ throw new RuntimeException("Managed to obtain a system logger without permission");
+ }
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ System.out.println("Got expected exception for system logger: " + acx);
+ }
+
+ if (hasRequiredPermissions) {
+ // if we don't have permissions sysSink will be null.
+ testLogger(provider, loggerDescMap, "foo", null,
+ PlatformLogger.Bridge.convert(sysLogger1), sysSink);
+ }
+
+ Logger appLogger2 =
+ System.getLogger("foo", loggerBundle);
+ loggerDescMap.put(appLogger2, "System.getLogger(\"foo\", loggerBundle)");
+
+ if (appLogger2 == appLogger1) {
+ throw new RuntimeException("identical loggers");
+ }
+
+ if (provider.system.contains(appLogger2)) {
+ throw new RuntimeException("localized app logger in system map");
+ }
+ if (provider.user.contains(appLogger2)) {
+ throw new RuntimeException("localized app logger in appplication map");
+ }
+
+ testLogger(provider, loggerDescMap, "foo", loggerBundle,
+ PlatformLogger.Bridge.convert(appLogger2), appSink);
+
+ Logger sysLogger2 = null;
+ try {
+ sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class);
+ loggerDescMap.put(sysLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, Thread.class)");
+ if (!hasRequiredPermissions) {
+ throw new RuntimeException("Managed to obtain a system logger without permission");
+ }
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ System.out.println("Got expected exception for localized system logger: " + acx);
+ }
+ if (hasRequiredPermissions && appLogger2 == sysLogger2) {
+ throw new RuntimeException("identical loggers");
+ }
+ if (hasRequiredPermissions && sysLogger2 == sysLogger1) {
+ throw new RuntimeException("identical loggers");
+ }
+ if (hasRequiredPermissions && provider.user.contains(sysLogger2)) {
+ throw new RuntimeException("localized sys logger in appplication map");
+ }
+ if (hasRequiredPermissions && provider.system.contains(sysLogger2)) {
+ throw new RuntimeException("localized sys logger not in system map");
+ }
+
+ if (hasRequiredPermissions) {
+ // if we don't have permissions sysSink will be null.
+ testLogger(provider, loggerDescMap, "foo", loggerBundle,
+ PlatformLogger.Bridge.convert(sysLogger2), sysSink);
+ }
+
+ }
+
+ public static class Foo {
+
+ }
+
+ static void verbose(String msg) {
+ if (VERBOSE) {
+ System.out.println(msg);
+ }
+ }
+
+ static void checkLogEvent(TestLoggerFinder provider, String desc,
+ TestLoggerFinder.LogEvent expected) {
+ TestLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (!Objects.equals(expected, actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+
+ static void checkLogEvent(TestLoggerFinder provider, String desc,
+ TestLoggerFinder.LogEvent expected, boolean expectNotNull) {
+ TestLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (actual == null && !expectNotNull) return;
+ if (actual != null && !expectNotNull) {
+ throw new RuntimeException("Unexpected log event found for " + desc
+ + "\n\tgot: " + actual);
+ }
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+
+ static Supplier<String> logpMessage(ResourceBundle bundle,
+ String className, String methodName, Supplier<String> msg) {
+ if (BEST_EFFORT_FOR_LOGP && bundle == null
+ && (className != null || methodName != null)) {
+ final String cName = className == null ? "" : className;
+ final String mName = methodName == null ? "" : methodName;
+ return () -> String.format("[%s %s] %s", cName, mName, msg.get());
+ } else {
+ return msg;
+ }
+ }
+
+ static String logpMessage(ResourceBundle bundle,
+ String className, String methodName, String msg) {
+ if (BEST_EFFORT_FOR_LOGP && bundle == null
+ && (className != null || methodName != null)) {
+ final String cName = className == null ? "" : className;
+ final String mName = methodName == null ? "" : methodName;
+ return String.format("[%s %s] %s", cName, mName, msg == null ? "" : msg);
+ } else {
+ return msg;
+ }
+ }
+
+ // Calls the methods defined on LogProducer and verify the
+ // parameters received by the underlying TestLoggerFinder.LoggerImpl
+ // logger.
+ private static void testLogger(TestLoggerFinder provider,
+ Map<Object, String> loggerDescMap,
+ String name,
+ ResourceBundle loggerBundle,
+ PlatformLogger.Bridge logger,
+ TestLoggerFinder.LoggerImpl sink) {
+
+ if (loggerDescMap.get(logger) == null) {
+ throw new RuntimeException("Test bug: Missing description");
+ }
+ System.out.println("Testing " + loggerDescMap.get(logger) +" [" + logger + "]");
+
+ Foo foo = new Foo();
+ String fooMsg = foo.toString();
+ System.out.println("\tlogger.log(messageLevel, fooMsg)");
+ System.out.println("\tlogger.<level>(fooMsg)");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.log(messageLevel, fooMsg): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ Level expectedMessageLevel = julToSpiMap.get(messageLevel);
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
+ name, expectedMessageLevel, loggerBundle,
+ fooMsg, null, (Throwable)null, (Object[])null);
+ logger.log(messageLevel, fooMsg);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ Supplier<String> supplier = new Supplier<String>() {
+ @Override
+ public String get() {
+ return this.toString();
+ }
+ };
+ System.out.println("\tlogger.log(messageLevel, supplier)");
+ System.out.println("\tlogger.<level>(supplier)");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.log(messageLevel, supplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ Level expectedMessageLevel = julToSpiMap.get(messageLevel);
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
+ name, expectedMessageLevel, (ResourceBundle) null,
+ null, supplier, (Throwable)null, (Object[])null);
+ logger.log(messageLevel, supplier);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ String format = "two params [{1} {2}]";
+ Object arg1 = foo;
+ Object arg2 = fooMsg;
+ System.out.println("\tlogger.log(messageLevel, format, arg1, arg2)");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.log(messageLevel, format, foo, fooMsg): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ Level expectedMessageLevel = julToSpiMap.get(messageLevel);
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
+ name, expectedMessageLevel, loggerBundle,
+ format, null, (Throwable)null, arg1, arg2);
+ logger.log(messageLevel, format, arg1, arg2);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ Throwable thrown = new Exception("OK: log me!");
+ System.out.println("\tlogger.log(messageLevel, fooMsg, thrown)");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.log(messageLevel, fooMsg, thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ Level expectedMessageLevel = julToSpiMap.get(messageLevel);
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
+ name, expectedMessageLevel, loggerBundle,
+ fooMsg, null, thrown, (Object[])null);
+ logger.log(messageLevel, fooMsg, thrown);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ System.out.println("\tlogger.log(messageLevel, thrown, supplier)");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.log(messageLevel, thrown, supplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ Level expectedMessageLevel = julToSpiMap.get(messageLevel);
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
+ name, expectedMessageLevel, (ResourceBundle)null,
+ null, supplier, thrown, (Object[])null);
+ logger.log(messageLevel, thrown, supplier);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ String sourceClass = "blah.Blah";
+ String sourceMethod = "blih";
+ System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, fooMsg)");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, fooMsg): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ Level expectedMessageLevel = julToSpiMap.get(messageLevel);
+ boolean isLoggable = loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0;
+ TestLoggerFinder.LogEvent expected =
+ isLoggable || loggerBundle != null && BEST_EFFORT_FOR_LOGP?
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ isLoggable,
+ name, expectedMessageLevel, loggerBundle,
+ logpMessage(loggerBundle, sourceClass, sourceMethod, fooMsg),
+ null, (Throwable)null, (Object[]) null) : null;
+ logger.logp(messageLevel, sourceClass, sourceMethod, fooMsg);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, supplier)");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, supplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ Level expectedMessageLevel = julToSpiMap.get(messageLevel);
+ boolean isLoggable = loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0;
+ TestLoggerFinder.LogEvent expected = isLoggable ?
+ TestLoggerFinder.LogEvent.ofp(BEST_EFFORT_FOR_LOGP,
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ isLoggable,
+ name, expectedMessageLevel, null, null,
+ logpMessage(null, sourceClass, sourceMethod, supplier),
+ (Throwable)null, (Object[]) null)) : null;
+ logger.logp(messageLevel, sourceClass, sourceMethod, supplier);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, format, arg1, arg2)");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, format, arg1, arg2): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ Level expectedMessageLevel = julToSpiMap.get(messageLevel);
+ boolean isLoggable = loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0;
+ TestLoggerFinder.LogEvent expected =
+ isLoggable || loggerBundle != null && BEST_EFFORT_FOR_LOGP?
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
+ name, expectedMessageLevel, loggerBundle,
+ logpMessage(loggerBundle, sourceClass, sourceMethod, format),
+ null, (Throwable)null, arg1, arg2) : null;
+ logger.logp(messageLevel, sourceClass, sourceMethod, format, arg1, arg2);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, fooMsg, thrown)");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, fooMsg, thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ Level expectedMessageLevel = julToSpiMap.get(messageLevel);
+ boolean isLoggable = loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0;
+ TestLoggerFinder.LogEvent expected =
+ isLoggable || loggerBundle != null && BEST_EFFORT_FOR_LOGP ?
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
+ name, expectedMessageLevel, loggerBundle,
+ logpMessage(loggerBundle, sourceClass, sourceMethod, fooMsg),
+ null, thrown, (Object[])null) : null;
+ logger.logp(messageLevel, sourceClass, sourceMethod, fooMsg, thrown);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, thrown, supplier)");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, thrown, supplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ Level expectedMessageLevel = julToSpiMap.get(messageLevel);
+ boolean isLoggable = loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0;
+ TestLoggerFinder.LogEvent expected = isLoggable ?
+ TestLoggerFinder.LogEvent.ofp(BEST_EFFORT_FOR_LOGP,
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
+ name, expectedMessageLevel, null, null,
+ logpMessage(null, sourceClass, sourceMethod, supplier),
+ thrown, (Object[])null)) : null;
+ logger.logp(messageLevel, sourceClass, sourceMethod, thrown, supplier);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ ResourceBundle bundle = ResourceBundle.getBundle(MyBundle.class.getName());
+ System.out.println("\tlogger.logrb(messageLevel, bundle, format, arg1, arg2)");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.logrb(messageLevel, bundle, format, arg1, arg2): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ Level expectedMessageLevel = julToSpiMap.get(messageLevel);
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
+ name, expectedMessageLevel, bundle,
+ format, null, (Throwable)null, arg1, arg2);
+ logger.logrb(messageLevel, bundle, format, arg1, arg2);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ System.out.println("\tlogger.logrb(messageLevel, bundle, msg, thrown)");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.logrb(messageLevel, bundle, msg, thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ Level expectedMessageLevel = julToSpiMap.get(messageLevel);
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
+ name, expectedMessageLevel, bundle,
+ fooMsg, null, thrown, (Object[])null);
+ logger.logrb(messageLevel, bundle, fooMsg, thrown);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ System.out.println("\tlogger.logrb(messageLevel, sourceClass, sourceMethod, bundle, format, arg1, arg2)");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.logrb(messageLevel, sourceClass, sourceMethod, bundle, format, arg1, arg2): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ Level expectedMessageLevel = julToSpiMap.get(messageLevel);
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
+ name, expectedMessageLevel, bundle,
+ format, null, (Throwable)null, arg1, arg2);
+ logger.logrb(messageLevel, sourceClass, sourceMethod, bundle, format, arg1, arg2);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ System.out.println("\tlogger.logrb(messageLevel, sourceClass, sourceMethod, bundle, msg, thrown)");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.logrb(messageLevel, sourceClass, sourceMethod, bundle, msg, thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ Level expectedMessageLevel = julToSpiMap.get(messageLevel);
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
+ name, expectedMessageLevel, bundle,
+ fooMsg, null, thrown, (Object[])null);
+ logger.logrb(messageLevel, sourceClass, sourceMethod, bundle, fooMsg, thrown);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+ }
+
+ final static class PermissionsBuilder {
+ final Permissions perms;
+ public PermissionsBuilder() {
+ this(new Permissions());
+ }
+ public PermissionsBuilder(Permissions perms) {
+ this.perms = perms;
+ }
+ public PermissionsBuilder add(Permission p) {
+ perms.add(p);
+ return this;
+ }
+ public PermissionsBuilder addAll(PermissionCollection col) {
+ if (col != null) {
+ for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
+ perms.add(e.nextElement());
+ }
+ }
+ return this;
+ }
+ public Permissions toPermissions() {
+ final PermissionsBuilder builder = new PermissionsBuilder();
+ builder.addAll(perms);
+ return builder.perms;
+ }
+ }
+
+ public static class SimplePolicy extends Policy {
+ final static RuntimePermission CONTROL = LOGGERFINDER_PERMISSION;
+ final static RuntimePermission ACCESS_LOGGER = new RuntimePermission("accessClassInPackage.jdk.internal.logger");
+ final static RuntimePermission ACCESS_LOGGING = new RuntimePermission("accessClassInPackage.sun.util.logging");
+
+ final Permissions permissions;
+ final Permissions allPermissions;
+ final ThreadLocal<AtomicBoolean> allowControl;
+ final ThreadLocal<AtomicBoolean> allowAccess;
+ final ThreadLocal<AtomicBoolean> allowAll;
+ public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl,
+ ThreadLocal<AtomicBoolean> allowAccess,
+ ThreadLocal<AtomicBoolean> allowAll) {
+ this.allowControl = allowControl;
+ this.allowAccess = allowAccess;
+ this.allowAll = allowAll;
+ permissions = new Permissions();
+ allPermissions = new PermissionsBuilder()
+ .add(new java.security.AllPermission())
+ .toPermissions();
+ }
+
+ Permissions getPermissions() {
+ if (allowControl.get().get() || allowAccess.get().get() || allowAll.get().get()) {
+ PermissionsBuilder builder = new PermissionsBuilder()
+ .addAll(permissions);
+ if (allowControl.get().get()) {
+ builder.add(CONTROL);
+ }
+ if (allowAccess.get().get()) {
+ builder.add(ACCESS_LOGGER);
+ builder.add(ACCESS_LOGGING);
+ }
+ if (allowAll.get().get()) {
+ builder.addAll(allPermissions);
+ }
+ return builder.toPermissions();
+ }
+ return permissions;
+ }
+
+ @Override
+ public boolean implies(ProtectionDomain domain, Permission permission) {
+ return getPermissions().implies(permission);
+ }
+
+ @Override
+ public PermissionCollection getPermissions(CodeSource codesource) {
+ return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
+ }
+
+ @Override
+ public PermissionCollection getPermissions(ProtectionDomain domain) {
+ return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/BaseLoggerBridgeTest/CustomSystemClassLoader.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.security.AllPermission;
+import java.security.Permissions;
+import java.security.ProtectionDomain;
+
+
+/**
+ * A custom ClassLoader to load the concrete LoggerFinder class
+ * with all permissions.
+ *
+ * @author danielfuchs
+ */
+public class CustomSystemClassLoader extends ClassLoader {
+
+
+ Class<?> finderClass = null;
+
+ public CustomSystemClassLoader() {
+ super();
+ }
+ public CustomSystemClassLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ private Class<?> defineFinderClass(String name)
+ throws ClassNotFoundException {
+ final Object obj = getClassLoadingLock(name);
+ synchronized(obj) {
+ if (finderClass != null) return finderClass;
+
+ URL url = this.getClass().getProtectionDomain().getCodeSource().getLocation();
+ File file = new File(url.getPath(), name+".class");
+ if (file.canRead()) {
+ try {
+ byte[] b = Files.readAllBytes(file.toPath());
+ Permissions perms = new Permissions();
+ perms.add(new AllPermission());
+ finderClass = defineClass(
+ name, b, 0, b.length, new ProtectionDomain(
+ this.getClass().getProtectionDomain().getCodeSource(),
+ perms));
+ System.out.println("Loaded " + name);
+ return finderClass;
+ } catch (Throwable ex) {
+ ex.printStackTrace();
+ throw new ClassNotFoundException(name, ex);
+ }
+ } else {
+ throw new ClassNotFoundException(name,
+ new IOException(file.toPath() + ": can't read"));
+ }
+ }
+ }
+
+ @Override
+ public synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ if (name.endsWith("$BaseLoggerFinder")) {
+ Class<?> c = defineFinderClass(name);
+ if (resolve) {
+ resolveClass(c);
+ }
+ return c;
+ }
+ return super.loadClass(name, resolve);
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ if (name.endsWith("$BaseLoggerFinder")) {
+ return defineFinderClass(name);
+ }
+ return super.findClass(name);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/BaseLoggerBridgeTest/META-INF/services/java.lang.System$LoggerFinder Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,1 @@
+BaseLoggerBridgeTest$BaseLoggerFinder
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/BasePlatformLoggerTest/BasePlatformLoggerTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,732 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.ResourceBundle;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Supplier;
+import java.lang.System.LoggerFinder;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.security.AccessControlException;
+import java.util.stream.Stream;
+import sun.util.logging.PlatformLogger;
+
+/**
+ * @test
+ * @bug 8140364
+ * @summary JDK implementation specific unit test for JDK internal API.
+ * Tests a naive implementation of System.Logger, and in particular
+ * the default mapping provided by PlatformLogger.
+ * @modules java.base/sun.util.logging
+ * @build CustomSystemClassLoader BasePlatformLoggerTest
+ * @run main/othervm -Djava.system.class.loader=CustomSystemClassLoader BasePlatformLoggerTest NOSECURITY
+ * @run main/othervm -Djava.system.class.loader=CustomSystemClassLoader BasePlatformLoggerTest NOPERMISSIONS
+ * @run main/othervm -Djava.system.class.loader=CustomSystemClassLoader BasePlatformLoggerTest WITHPERMISSIONS
+ * @author danielfuchs
+ */
+public class BasePlatformLoggerTest {
+
+ public static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+
+ final static AtomicLong sequencer = new AtomicLong();
+ final static boolean VERBOSE = false;
+ static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+ static final ThreadLocal<AtomicBoolean> allowAccess = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+ static final ThreadLocal<AtomicBoolean> allowAll = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+
+ static final Class<?> providerClass;
+ static {
+ try {
+ providerClass = ClassLoader.getSystemClassLoader().loadClass("BasePlatformLoggerTest$BaseLoggerFinder");
+ } catch (ClassNotFoundException ex) {
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+ static final PlatformLogger.Level[] julLevels = {
+ PlatformLogger.Level.ALL,
+ PlatformLogger.Level.FINEST,
+ PlatformLogger.Level.FINER,
+ PlatformLogger.Level.FINE,
+ PlatformLogger.Level.CONFIG,
+ PlatformLogger.Level.INFO,
+ PlatformLogger.Level.WARNING,
+ PlatformLogger.Level.SEVERE,
+ PlatformLogger.Level.OFF,
+ };
+
+ static final Level[] mappedLevels = {
+ Level.ALL, // ALL
+ Level.TRACE, // FINEST
+ Level.TRACE, // FINER
+ Level.DEBUG, // FINE
+ Level.DEBUG, // CONFIG
+ Level.INFO, // INFO
+ Level.WARNING, // WARNING
+ Level.ERROR, // SEVERE
+ Level.OFF, // OFF
+ };
+
+ final static Map<PlatformLogger.Level, Level> julToSpiMap;
+ static {
+ Map<PlatformLogger.Level, Level> map = new HashMap<>();
+ if (mappedLevels.length != julLevels.length) {
+ throw new ExceptionInInitializerError("Array lengths differ"
+ + "\n\tjulLevels=" + Arrays.deepToString(julLevels)
+ + "\n\tmappedLevels=" + Arrays.deepToString(mappedLevels));
+ }
+ for (int i=0; i<julLevels.length; i++) {
+ map.put(julLevels[i], mappedLevels[i]);
+ }
+ julToSpiMap = Collections.unmodifiableMap(map);
+ }
+
+ public static class MyBundle extends ResourceBundle {
+
+ final ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>();
+
+ @Override
+ protected Object handleGetObject(String key) {
+ if (key.contains(" (translated)")) {
+ throw new RuntimeException("Unexpected key: " + key);
+ }
+ return map.computeIfAbsent(key, k -> k + " (translated)");
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ return Collections.enumeration(map.keySet());
+ }
+
+ }
+ public static class MyLoggerBundle extends MyBundle {
+
+ }
+
+
+ public static interface TestLoggerFinder {
+ final ConcurrentHashMap<String, LoggerImpl> system = new ConcurrentHashMap<>();
+ final ConcurrentHashMap<String, LoggerImpl> user = new ConcurrentHashMap<>();
+ public Queue<LogEvent> eventQueue = new ArrayBlockingQueue<>(128);
+
+ public static final class LogEvent implements Cloneable {
+
+ public LogEvent() {
+ this(sequencer.getAndIncrement());
+ }
+
+ LogEvent(long sequenceNumber) {
+ this.sequenceNumber = sequenceNumber;
+ }
+
+ long sequenceNumber;
+ boolean isLoggable;
+ String loggerName;
+ Level level;
+ ResourceBundle bundle;
+ Throwable thrown;
+ Object[] args;
+ Supplier<String> supplier;
+ String msg;
+
+ Object[] toArray() {
+ return new Object[] {
+ sequenceNumber,
+ isLoggable,
+ loggerName,
+ level,
+ bundle,
+ thrown,
+ args,
+ supplier,
+ msg,
+ };
+ }
+
+ @Override
+ public String toString() {
+ return Arrays.deepToString(toArray());
+ }
+
+
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof LogEvent
+ && Objects.deepEquals(this.toArray(), ((LogEvent)obj).toArray());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(toArray());
+ }
+
+ public LogEvent cloneWith(long sequenceNumber)
+ throws CloneNotSupportedException {
+ LogEvent cloned = (LogEvent)super.clone();
+ cloned.sequenceNumber = sequenceNumber;
+ return cloned;
+ }
+
+ public static LogEvent of(boolean isLoggable, String name,
+ Level level, ResourceBundle bundle,
+ String key, Throwable thrown) {
+ LogEvent evt = new LogEvent();
+ evt.isLoggable = isLoggable;
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = null;
+ evt.bundle = bundle;
+ evt.thrown = thrown;
+ evt.supplier = null;
+ evt.msg = key;
+ return evt;
+ }
+
+ public static LogEvent of(boolean isLoggable, String name,
+ Level level, Throwable thrown, Supplier<String> supplier) {
+ LogEvent evt = new LogEvent();
+ evt.isLoggable = isLoggable;
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = null;
+ evt.bundle = null;
+ evt.thrown = thrown;
+ evt.supplier = supplier;
+ evt.msg = null;
+ return evt;
+ }
+
+ public static LogEvent of(boolean isLoggable, String name,
+ Level level, ResourceBundle bundle,
+ String key, Object... params) {
+ LogEvent evt = new LogEvent();
+ evt.isLoggable = isLoggable;
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = params;
+ evt.bundle = bundle;
+ evt.thrown = null;
+ evt.supplier = null;
+ evt.msg = key;
+ return evt;
+ }
+
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ Level level, ResourceBundle bundle,
+ String key, Supplier<String> supplier,
+ Throwable thrown, Object... params) {
+ LogEvent evt = new LogEvent(sequenceNumber);
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = params;
+ evt.bundle = bundle;
+ evt.thrown = thrown;
+ evt.supplier = supplier;
+ evt.msg = key;
+ evt.isLoggable = isLoggable;
+ return evt;
+ }
+
+ }
+
+ public class LoggerImpl implements Logger {
+ private final String name;
+ private Level level = Level.INFO;
+
+ public LoggerImpl(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean isLoggable(Level level) {
+ return this.level != Level.OFF && this.level.getSeverity() <= level.getSeverity();
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle, String key, Throwable thrown) {
+ log(LogEvent.of(isLoggable(level), this.name, level, bundle, key, thrown));
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle, String format, Object... params) {
+ log(LogEvent.of(isLoggable(level), name, level, bundle, format, params));
+ }
+
+ void log(LogEvent event) {
+ eventQueue.add(event);
+ }
+
+ @Override
+ public void log(Level level, Supplier<String> msgSupplier) {
+ log(LogEvent.of(isLoggable(level), name, level, null, msgSupplier));
+ }
+
+ @Override
+ public void log(Level level, Supplier<String> msgSupplier, Throwable thrown) {
+ log(LogEvent.of(isLoggable(level), name, level, thrown, msgSupplier));
+ }
+ }
+
+ public Logger getLogger(String name, Class<?> caller);
+ }
+
+ public static class BaseLoggerFinder extends LoggerFinder implements TestLoggerFinder {
+ @Override
+ public Logger getLogger(String name, Class<?> caller) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGERFINDER_PERMISSION);
+ }
+ PrivilegedAction<ClassLoader> pa = () -> caller.getClassLoader();
+ ClassLoader callerLoader = AccessController.doPrivileged(pa);
+ if (callerLoader == null) {
+ return system.computeIfAbsent(name, (n) -> new LoggerImpl(n));
+ } else {
+ return user.computeIfAbsent(name, (n) -> new LoggerImpl(n));
+ }
+ }
+ }
+
+ static PlatformLogger getPlatformLogger(String name) {
+ boolean old = allowAccess.get().get();
+ allowAccess.get().set(true);
+ try {
+ return PlatformLogger.getLogger(name);
+ } finally {
+ allowAccess.get().set(old);
+ }
+ }
+
+ static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS};
+
+ static void setSecurityManager() {
+ if (System.getSecurityManager() == null) {
+ Policy.setPolicy(new SimplePolicy(allowControl, allowAccess, allowAll));
+ System.setSecurityManager(new SecurityManager());
+ }
+ }
+
+ public static void main(String[] args) {
+ if (args.length == 0)
+ args = new String[] {
+ "NOSECURITY",
+ "NOPERMISSIONS",
+ "WITHPERMISSIONS"
+ };
+
+
+ Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> {
+ TestLoggerFinder provider;
+ switch (testCase) {
+ case NOSECURITY:
+ System.out.println("\n*** Without Security Manager\n");
+ provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
+ test(provider, true);
+ System.out.println("Tetscase count: " + sequencer.get());
+ break;
+ case NOPERMISSIONS:
+ System.out.println("\n*** With Security Manager, without permissions\n");
+ setSecurityManager();
+ try {
+ provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
+ throw new RuntimeException("Expected exception not raised");
+ } catch (AccessControlException x) {
+ if (!LOGGERFINDER_PERMISSION.equals(x.getPermission())) {
+ throw new RuntimeException("Unexpected permission check", x);
+ }
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
+ } finally {
+ allowControl.get().set(control);
+ }
+ }
+ test(provider, false);
+ System.out.println("Tetscase count: " + sequencer.get());
+ break;
+ case WITHPERMISSIONS:
+ System.out.println("\n*** With Security Manager, with control permission\n");
+ setSecurityManager();
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
+ test(provider, true);
+ } finally {
+ allowControl.get().set(control);
+ }
+ break;
+ default:
+ throw new RuntimeException("Unknown test case: " + testCase);
+ }
+ });
+ System.out.println("\nPASSED: Tested " + sequencer.get() + " cases.");
+ }
+
+ public static void test(TestLoggerFinder provider, boolean hasRequiredPermissions) {
+
+ final Map<PlatformLogger, String> loggerDescMap = new HashMap<>();
+
+ TestLoggerFinder.LoggerImpl appSink;
+ boolean before = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ appSink = TestLoggerFinder.LoggerImpl.class.cast(
+ provider.getLogger("foo", BasePlatformLoggerTest.class));
+ } finally {
+ allowControl.get().set(before);
+ }
+
+ TestLoggerFinder.LoggerImpl sysSink = null;
+ before = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ sysSink = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class));
+ } finally {
+ allowControl.get().set(before);
+ }
+
+ if (hasRequiredPermissions && appSink == sysSink) {
+ throw new RuntimeException("identical loggers");
+ }
+
+ if (provider.system.contains(appSink)) {
+ throw new RuntimeException("app logger in system map");
+ }
+ if (!provider.user.contains(appSink)) {
+ throw new RuntimeException("app logger not in appplication map");
+ }
+ if (hasRequiredPermissions && provider.user.contains(sysSink)) {
+ throw new RuntimeException("sys logger in appplication map");
+ }
+ if (hasRequiredPermissions && !provider.system.contains(sysSink)) {
+ throw new RuntimeException("sys logger not in system map");
+ }
+
+ PlatformLogger platform = getPlatformLogger("foo");
+ loggerDescMap.put(platform, "PlatformLogger.getLogger(\"foo\")");
+
+ testLogger(provider, loggerDescMap, "foo", null, platform, sysSink);
+ }
+
+ public static class Foo {
+
+ }
+
+ static void verbose(String msg) {
+ if (VERBOSE) {
+ System.out.println(msg);
+ }
+ }
+
+ static void checkLogEvent(TestLoggerFinder provider, String desc,
+ TestLoggerFinder.LogEvent expected) {
+ TestLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+
+ static void checkLogEvent(TestLoggerFinder provider, String desc,
+ TestLoggerFinder.LogEvent expected, boolean expectNotNull) {
+ TestLoggerFinder.LogEvent actual = provider.eventQueue.poll();
+ if (actual == null && !expectNotNull) return;
+ if (actual != null && !expectNotNull) {
+ throw new RuntimeException("Unexpected log event found for " + desc
+ + "\n\tgot: " + actual);
+ }
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+
+ // Calls the methods defined on LogProducer and verify the
+ // parameters received by the underlying TestLoggerFinder.LoggerImpl
+ // logger.
+ private static void testLogger(TestLoggerFinder provider,
+ Map<PlatformLogger, String> loggerDescMap,
+ String name,
+ ResourceBundle loggerBundle,
+ PlatformLogger logger,
+ TestLoggerFinder.LoggerImpl sink) {
+
+ System.out.println("Testing " + loggerDescMap.get(logger));
+
+ Foo foo = new Foo();
+ String fooMsg = foo.toString();
+ System.out.println("\tlogger.<level>(fooMsg)");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (PlatformLogger.Level messageLevel :julLevels) {
+ Level expectedMessageLevel = julToSpiMap.get(messageLevel);
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
+ name, expectedMessageLevel, loggerBundle,
+ fooMsg, null, (Throwable)null, (Object[])null);
+ String desc2 = "logger." + messageLevel.toString().toLowerCase()
+ + "(fooMsg): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ if (messageLevel == PlatformLogger.Level.FINEST) {
+ logger.finest(fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == PlatformLogger.Level.FINER) {
+ logger.finer(fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == PlatformLogger.Level.FINE) {
+ logger.fine(fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == PlatformLogger.Level.CONFIG) {
+ logger.config(fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == PlatformLogger.Level.INFO) {
+ logger.info(fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == PlatformLogger.Level.WARNING) {
+ logger.warning(fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == PlatformLogger.Level.SEVERE) {
+ logger.severe(fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ }
+ }
+ }
+
+ Throwable thrown = new Exception("OK: log me!");
+ System.out.println("\tlogger.<level>(msg, thrown)");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (PlatformLogger.Level messageLevel :julLevels) {
+ Level expectedMessageLevel = julToSpiMap.get(messageLevel);
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
+ name, expectedMessageLevel, (ResourceBundle) null,
+ fooMsg, null, (Throwable)thrown, (Object[])null);
+ String desc2 = "logger." + messageLevel.toString().toLowerCase()
+ + "(msg, thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ if (messageLevel == PlatformLogger.Level.FINEST) {
+ logger.finest(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == PlatformLogger.Level.FINER) {
+ logger.finer(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == PlatformLogger.Level.FINE) {
+ logger.fine(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == PlatformLogger.Level.CONFIG) {
+ logger.config(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == PlatformLogger.Level.INFO) {
+ logger.info(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == PlatformLogger.Level.WARNING) {
+ logger.warning(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == PlatformLogger.Level.SEVERE) {
+ logger.severe(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected);
+ }
+ }
+ }
+
+ String format = "two params [{1} {2}]";
+ Object arg1 = foo;
+ Object arg2 = fooMsg;
+ System.out.println("\tlogger.<level>(format, arg1, arg2)");
+ for (Level loggerLevel : Level.values()) {
+ sink.level = loggerLevel;
+ for (PlatformLogger.Level messageLevel :julLevels) {
+ Level expectedMessageLevel = julToSpiMap.get(messageLevel);
+ TestLoggerFinder.LogEvent expected =
+ TestLoggerFinder.LogEvent.of(
+ sequencer.get(),
+ loggerLevel != Level.OFF && expectedMessageLevel.compareTo(loggerLevel) >= 0,
+ name, expectedMessageLevel, (ResourceBundle) null,
+ format, null, (Throwable)null, foo, fooMsg);
+ String desc2 = "logger." + messageLevel.toString().toLowerCase()
+ + "(format, foo, fooMsg): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ if (messageLevel == PlatformLogger.Level.FINEST) {
+ logger.finest(format, foo, fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == PlatformLogger.Level.FINER) {
+ logger.finer(format, foo, fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == PlatformLogger.Level.FINE) {
+ logger.fine(format, foo, fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == PlatformLogger.Level.CONFIG) {
+ logger.config(format, foo, fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == PlatformLogger.Level.INFO) {
+ logger.info(format, foo, fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == PlatformLogger.Level.WARNING) {
+ logger.warning(format, foo, fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == PlatformLogger.Level.SEVERE) {
+ logger.severe(format, foo, fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ }
+ }
+ }
+
+ }
+
+ final static class PermissionsBuilder {
+ final Permissions perms;
+ public PermissionsBuilder() {
+ this(new Permissions());
+ }
+ public PermissionsBuilder(Permissions perms) {
+ this.perms = perms;
+ }
+ public PermissionsBuilder add(Permission p) {
+ perms.add(p);
+ return this;
+ }
+ public PermissionsBuilder addAll(PermissionCollection col) {
+ if (col != null) {
+ for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
+ perms.add(e.nextElement());
+ }
+ }
+ return this;
+ }
+ public Permissions toPermissions() {
+ final PermissionsBuilder builder = new PermissionsBuilder();
+ builder.addAll(perms);
+ return builder.perms;
+ }
+ }
+
+ public static class SimplePolicy extends Policy {
+ final static RuntimePermission CONTROL = LOGGERFINDER_PERMISSION;
+ final static RuntimePermission ACCESS_LOGGING = new RuntimePermission("accessClassInPackage.sun.util.logging");
+
+ final Permissions permissions;
+ final Permissions allPermissions;
+ final ThreadLocal<AtomicBoolean> allowControl;
+ final ThreadLocal<AtomicBoolean> allowAccess;
+ final ThreadLocal<AtomicBoolean> allowAll;
+ public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl,
+ ThreadLocal<AtomicBoolean> allowAccess,
+ ThreadLocal<AtomicBoolean> allowAll) {
+ this.allowControl = allowControl;
+ this.allowAccess = allowAccess;
+ this.allowAll = allowAll;
+ permissions = new Permissions();
+ allPermissions = new PermissionsBuilder()
+ .add(new java.security.AllPermission())
+ .toPermissions();
+ }
+
+ Permissions getPermissions() {
+ if (allowControl.get().get() || allowAccess.get().get() || allowAll.get().get()) {
+ PermissionsBuilder builder = new PermissionsBuilder()
+ .addAll(permissions);
+ if (allowControl.get().get()) {
+ builder.add(CONTROL);
+ }
+ if (allowAccess.get().get()) {
+ builder.add(ACCESS_LOGGING);
+ }
+ if (allowAll.get().get()) {
+ builder.addAll(allPermissions);
+ }
+ return builder.toPermissions();
+ }
+ return permissions;
+ }
+
+ @Override
+ public boolean implies(ProtectionDomain domain, Permission permission) {
+ return getPermissions().implies(permission);
+ }
+
+ @Override
+ public PermissionCollection getPermissions(CodeSource codesource) {
+ return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
+ }
+
+ @Override
+ public PermissionCollection getPermissions(ProtectionDomain domain) {
+ return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/BasePlatformLoggerTest/CustomSystemClassLoader.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.security.AllPermission;
+import java.security.Permissions;
+import java.security.ProtectionDomain;
+
+
+/**
+ * A custom ClassLoader to load the concrete LoggerFinder class
+ * with all permissions.
+ *
+ * @author danielfuchs
+ */
+public class CustomSystemClassLoader extends ClassLoader {
+
+
+ Class<?> finderClass = null;
+
+ public CustomSystemClassLoader() {
+ super();
+ }
+ public CustomSystemClassLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ private Class<?> defineFinderClass(String name)
+ throws ClassNotFoundException {
+ final Object obj = getClassLoadingLock(name);
+ synchronized(obj) {
+ if (finderClass != null) return finderClass;
+
+ URL url = this.getClass().getProtectionDomain().getCodeSource().getLocation();
+ File file = new File(url.getPath(), name+".class");
+ if (file.canRead()) {
+ try {
+ byte[] b = Files.readAllBytes(file.toPath());
+ Permissions perms = new Permissions();
+ perms.add(new AllPermission());
+ finderClass = defineClass(
+ name, b, 0, b.length, new ProtectionDomain(
+ this.getClass().getProtectionDomain().getCodeSource(),
+ perms));
+ System.out.println("Loaded " + name);
+ return finderClass;
+ } catch (Throwable ex) {
+ ex.printStackTrace();
+ throw new ClassNotFoundException(name, ex);
+ }
+ } else {
+ throw new ClassNotFoundException(name,
+ new IOException(file.toPath() + ": can't read"));
+ }
+ }
+ }
+
+ @Override
+ public synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ if (name.endsWith("$BaseLoggerFinder")) {
+ Class<?> c = defineFinderClass(name);
+ if (resolve) {
+ resolveClass(c);
+ }
+ return c;
+ }
+ return super.loadClass(name, resolve);
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ if (name.endsWith("$BaseLoggerFinder")) {
+ return defineFinderClass(name);
+ }
+ return super.findClass(name);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/BasePlatformLoggerTest/META-INF/services/java.lang.System$LoggerFinder Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,1 @@
+BasePlatformLoggerTest$BaseLoggerFinder
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.BooleanSupplier;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.AllPermission;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import jdk.internal.logger.BootstrapLogger;
+import jdk.internal.logger.LazyLoggers;
+
+/*
+ * @test
+ * @bug 8140364
+ * @author danielfuchs
+ * @summary JDK implementation specific unit test for JDK internal artifacts.
+ Tests the behavior of bootstrap loggers (and SimpleConsoleLoggers
+ * too).
+ * @modules java.base/jdk.internal.logger
+ * @run main/othervm BootstrapLoggerTest NO_SECURITY
+ * @run main/othervm BootstrapLoggerTest SECURE
+ * @run main/othervm/timeout=120 BootstrapLoggerTest SECURE_AND_WAIT
+ */
+public class BootstrapLoggerTest {
+
+ static final Method awaitPending;
+ static final Method isAlive;
+ static final Field isBooted;
+ static final Field logManagerInitialized;
+ static {
+ try {
+ isBooted = BootstrapLogger.class.getDeclaredField("isBooted");
+ isBooted.setAccessible(true);
+ // private reflection hook that allows us to test wait until all
+ // the tasks pending in the BootstrapExecutor are finished.
+ awaitPending = BootstrapLogger.class
+ .getDeclaredMethod("awaitPendingTasks");
+ awaitPending.setAccessible(true);
+ // private reflection hook that allows us to test whether
+ // the BootstrapExecutor is alive.
+ isAlive = BootstrapLogger.class
+ .getDeclaredMethod("isAlive");
+ isAlive.setAccessible(true);
+ // private reflection hook that allows us to test whether the LogManager
+ // has initialized and registered with the BootstrapLogger class
+ logManagerInitialized = BootstrapLogger.class
+ .getDeclaredField("logManagerConfigured");
+ logManagerInitialized.setAccessible(true);
+ } catch (Exception ex) {
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+ static void awaitPending() {
+ try {
+ awaitPending.invoke(null);
+ } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+ ex.printStackTrace(LogStream.err);
+ }
+ }
+
+ /**
+ * We use an instance of this class to check what the logging system has
+ * printed on System.err.
+ */
+ public static class LogStream extends OutputStream {
+
+ final static PrintStream err = System.err;
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ public LogStream() {
+ super();
+ }
+
+ @Override
+ public synchronized void write(int b) {
+ baos.write(b);
+ err.write(b);
+ }
+
+ public String drain() {
+ awaitPending();
+ synchronized(this) {
+ String txt = baos.toString();
+ baos.reset();
+ return txt;
+ }
+ }
+ }
+
+ static enum TestCase {
+ NO_SECURITY, SECURE, SECURE_AND_WAIT
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (args == null || args.length == 0) {
+ args = new String[] { TestCase.SECURE_AND_WAIT.name() };
+ }
+ if (args.length > 1) throw new RuntimeException("Only one argument allowed");
+ TestCase test = TestCase.valueOf(args[0]);
+ System.err.println("Testing: " + test);
+
+
+ // private reflection hook that allows us to simulate a non booted VM
+ final AtomicBoolean vmBooted = new AtomicBoolean(false);
+ isBooted.set(null,(BooleanSupplier) () -> vmBooted.get());
+
+ // We replace System.err to check the messages that have been logged
+ // by the JUL ConsoleHandler and default SimpleConsoleLogger
+ // implementaion
+ final LogStream err = new LogStream();
+ System.setErr(new PrintStream(err));
+
+ if (BootstrapLogger.isBooted()) {
+ throw new RuntimeException("VM should not be booted!");
+ }
+ Logger logger = LazyLoggers.getLogger("foo.bar", Thread.class);
+
+ if (test != TestCase.NO_SECURITY) {
+ LogStream.err.println("Setting security manager");
+ Policy.setPolicy(new SimplePolicy());
+ System.setSecurityManager(new SecurityManager());
+ }
+
+ Level[] levels = {Level.INFO, Level.WARNING, Level.INFO};
+ int index = 0;
+ logger.log(levels[index], "Early message #" + (index+1)); index++;
+ logger.log(levels[index], "Early message #" + (index+1)); index++;
+ LogStream.err.println("VM Booted: " + vmBooted.get());
+ LogStream.err.println("LogManager initialized: " + logManagerInitialized.get(null));
+ logger.log(levels[index], "Early message #" + (index+1)); index++;
+ if (err.drain().contains("Early message")) {
+ // We're expecting that logger will be a LazyLogger wrapping a
+ // BootstrapLogger. The Bootstrap logger will stack the log messages
+ // it receives until the VM is booted.
+ // Since our private hook pretend that the VM is not booted yet,
+ // the logged messages shouldn't have reached System.err yet.
+ throw new RuntimeException("Early message logged while VM is not booted!");
+ }
+
+ // Now pretend that the VM is booted. Nothing should happen yet, until
+ // we try to log a new message.
+ vmBooted.getAndSet(true);
+ LogStream.err.println("VM Booted: " + vmBooted.get());
+ LogStream.err.println("LogManager initialized: " + logManagerInitialized.get(null));
+ if (!BootstrapLogger.isBooted()) {
+ throw new RuntimeException("VM should now be booted!");
+ }
+ if (((Boolean)logManagerInitialized.get(null)).booleanValue()) {
+ throw new RuntimeException("LogManager shouldn't be initialized yet!");
+ }
+
+ // Logging a message should cause the BootstrapLogger to replace itself
+ // by a 'real' logger in the LazyLogger. But since the LogManager isn't
+ // initialized yet, this should be a SimpleConsoleLogger...
+ logger.log(Level.INFO, "LOG#4: VM now booted: {0}", vmBooted.get());
+ logger.log(Level.DEBUG, "LOG#5: hi!");
+ SimplePolicy.allowAll.set(Boolean.TRUE);
+ WeakReference<Thread> threadRef = null;
+ ReferenceQueue<Thread> queue = new ReferenceQueue<>();
+ try {
+ Set<Thread> set = Thread.getAllStackTraces().keySet().stream()
+ .filter((t) -> t.getName().startsWith("BootstrapMessageLoggerTask-"))
+ .collect(Collectors.toSet());
+ set.stream().forEach(t -> LogStream.err.println("Found: " + t));
+ if (set.size() > 1) {
+ throw new RuntimeException("Too many bootsrap threads found");
+ }
+ Optional<Thread> t = set.stream().findFirst();
+ if (t.isPresent()) {
+ threadRef = new WeakReference<>(t.get(), queue);
+ }
+ } finally{
+ SimplePolicy.allowAll.set(Boolean.FALSE);
+ }
+ if (!BootstrapLogger.isBooted()) {
+ throw new RuntimeException("VM should still be booted!");
+ }
+ if (((Boolean)logManagerInitialized.get(null)).booleanValue()) {
+ throw new RuntimeException("LogManager shouldn't be initialized yet!");
+ }
+
+ // Now check that the early messages we had printed before the VM was
+ // booted have appeared on System.err...
+ String afterBoot = err.drain();
+ for (int i=0; i<levels.length; i++) {
+ String m = levels[i].getName()+": Early message #"+(i+1);
+ if (!afterBoot.contains(m)) {
+ throw new RuntimeException("System.err does not contain: "+m);
+ }
+ }
+ // check that the message logged *after* the VM was booted also printed.
+ if (!afterBoot.contains("INFO: LOG#4")) {
+ throw new RuntimeException("System.err does not contain: "
+ + "INFO: LOG#4");
+ }
+ // check that the debug message was not printed.
+ if (afterBoot.contains("LOG#5")) {
+ throw new RuntimeException("System.err contain: " + "LOG#5");
+ }
+ LogStream.err.println("VM Booted: " + vmBooted.get());
+ LogStream.err.println("LogManager initialized: " + logManagerInitialized.get(null));
+ if (!BootstrapLogger.isBooted()) {
+ throw new RuntimeException("VM should still be booted!");
+ }
+ if (((Boolean)logManagerInitialized.get(null)).booleanValue()) {
+ throw new RuntimeException("LogManager shouldn't be initialized yet!");
+ }
+
+ // Now we're going to use reflection to access JUL, and change
+ // the level of the "foo" logger.
+ // We're using reflection so that the test can also run in
+ // configurations where java.util.logging is not present.
+ boolean hasJUL = false;
+ SimplePolicy.allowAll.set(Boolean.TRUE);
+ try {
+ Class<?> loggerClass = Class.forName("java.util.logging.Logger");
+ Class<?> levelClass = Class.forName("java.util.logging.Level");
+ Class<?> handlerClass = Class.forName("java.util.logging.Handler");
+
+ // java.util.logging.Logger.getLogger("foo")
+ // .setLevel(java.util.logging.Level.FINEST);
+ Object fooLogger = loggerClass.getMethod("getLogger", String.class)
+ .invoke(null, "foo");
+ loggerClass.getMethod("setLevel", levelClass)
+ .invoke(fooLogger, levelClass.getField("FINEST").get(null));
+
+ // java.util.logging.Logger.getLogger("").getHandlers()[0]
+ // .setLevel(java.util.logging.Level.ALL);
+ Object rootLogger = loggerClass.getMethod("getLogger", String.class)
+ .invoke(null, "");
+ Object handlers = loggerClass.getMethod("getHandlers").
+ invoke(rootLogger);
+ handlerClass.getMethod("setLevel", levelClass)
+ .invoke(Array.get(handlers, 0), levelClass.getField("ALL")
+ .get(null));
+
+ hasJUL = true;
+ } catch (ClassNotFoundException x) {
+ LogStream.err.println("JUL is not present: class " + x.getMessage()
+ + " not found");
+ hasJUL = false;
+ } finally {
+ SimplePolicy.allowAll.set(Boolean.FALSE);
+ }
+
+ logger.log(Level.DEBUG, "hi now!");
+ String debug = err.drain();
+ if (hasJUL) {
+ if (!((Boolean)logManagerInitialized.get(null)).booleanValue()) {
+ throw new RuntimeException("LogManager should be initialized now!");
+ }
+ if (!debug.contains("FINE: hi now!")) {
+ throw new RuntimeException("System.err does not contain: "
+ + "FINE: hi now!");
+ }
+ } else {
+ if (debug.contains("hi now!")) {
+ throw new RuntimeException("System.err contains: " + "hi now!");
+ }
+ if (((Boolean)logManagerInitialized.get(null)).booleanValue()) {
+ throw new RuntimeException("LogManager shouldn't be initialized yet!");
+ }
+ Logger baz = System.getLogger("foo.bar.baz");
+ if (((Boolean)logManagerInitialized.get(null)).booleanValue()) {
+ throw new RuntimeException("LogManager shouldn't be initialized yet!");
+ }
+ }
+ Logger bazbaz = null;
+ SimplePolicy.allowAll.set(Boolean.TRUE);
+ try {
+ bazbaz = java.lang.System.LoggerFinder
+ .getLoggerFinder().getLogger("foo.bar.baz.baz", BootstrapLoggerTest.class);
+ } finally {
+ SimplePolicy.allowAll.set(Boolean.FALSE);
+ }
+ if (!((Boolean)logManagerInitialized.get(null)).booleanValue()) {
+ throw new RuntimeException("LogManager should be initialized now!");
+ }
+ Logger bazbaz2 = System.getLogger("foo.bar.baz.baz");
+ if (bazbaz2.getClass() != bazbaz.getClass()) {
+ throw new RuntimeException("bazbaz2.class != bazbaz.class ["
+ + bazbaz2.getClass() + " != "
+ + bazbaz.getClass() + "]");
+ }
+ if (hasJUL != bazbaz2.getClass().getName()
+ .equals("sun.util.logging.internal.LoggingProviderImpl$JULWrapper")) {
+ throw new RuntimeException("Unexpected class for bazbaz: "
+ + bazbaz.getClass().getName()
+ + "\n\t expected: "
+ + "sun.util.logging.internal.LoggingProviderImpl$JULWrapper");
+ }
+
+ // Now we're going to check that the thread of the BootstrapLogger
+ // executor terminates, and that the Executor is GC'ed after that.
+ // This will involve a bit of waiting, hence the timeout=120 in
+ // the @run line.
+ // If this test fails in timeout - we could envisage skipping this part,
+ // or adding some System property to configure the keep alive delay
+ // of the executor.
+ SimplePolicy.allowAll.set(Boolean.TRUE);
+ try {
+ Stream<Thread> stream = Thread.getAllStackTraces().keySet().stream();
+ stream.filter((t) -> t.getName().startsWith("BootstrapMessageLoggerTask-"))
+ .forEach(t -> LogStream.err.println(t));
+ stream = null;
+ if (threadRef != null && test == TestCase.SECURE_AND_WAIT) {
+ Thread t = threadRef.get();
+ if (t != null) {
+ if (!(Boolean)isAlive.invoke(null)) {
+ throw new RuntimeException("Executor already terminated");
+ } else {
+ LogStream.err.println("Executor still alive as expected.");
+ }
+ LogStream.err.println("Waiting for " + t.getName() + " to terminate (join)");
+ t.join(60_000);
+ t = null;
+ }
+ LogStream.err.println("Calling System.gc()");
+ System.gc();
+ LogStream.err.println("Waiting for BootstrapMessageLoggerTask to be gc'ed");
+ while (queue.remove(1000) == null) {
+ LogStream.err.println("Calling System.gc()");
+ System.gc();
+ }
+
+ // Call the reference here to make sure threadRef will not be
+ // eagerly garbage collected before the thread it references.
+ // otherwise, it might not be enqueued, resulting in the
+ // queue.remove() call above to always return null....
+ if (threadRef.get() != null) {
+ throw new RuntimeException("Reference should have been cleared");
+ }
+
+ LogStream.err.println("BootstrapMessageLoggerTask has been gc'ed");
+ // Wait for the executor to be gc'ed...
+ for (int i=0; i<10; i++) {
+ LogStream.err.println("Calling System.gc()");
+ System.gc();
+ if (!(Boolean)isAlive.invoke(null)) break;
+ // It would be unexpected that we reach here...
+ Thread.sleep(1000);
+ }
+
+ if ((Boolean)isAlive.invoke(null)) {
+ throw new RuntimeException("Executor still alive");
+ } else {
+ LogStream.err.println("Executor terminated as expected.");
+ }
+ } else {
+ LogStream.err.println("Not checking executor termination for " + test);
+ }
+ } finally {
+ SimplePolicy.allowAll.set(Boolean.FALSE);
+ }
+ LogStream.err.println(test.name() + ": PASSED");
+ }
+
+ final static class SimplePolicy extends Policy {
+ static final ThreadLocal<Boolean> allowAll = new ThreadLocal<Boolean>() {
+ @Override
+ protected Boolean initialValue() {
+ return Boolean.FALSE;
+ }
+ };
+
+ Permissions getPermissions() {
+ Permissions perms = new Permissions();
+ if (allowAll.get()) {
+ perms.add(new AllPermission());
+ }
+ return perms;
+ }
+
+ @Override
+ public boolean implies(ProtectionDomain domain, Permission permission) {
+ return getPermissions(domain).implies(permission);
+ }
+
+ @Override
+ public PermissionCollection getPermissions(CodeSource codesource) {
+ return getPermissions();
+ }
+
+ @Override
+ public PermissionCollection getPermissions(ProtectionDomain domain) {
+ return getPermissions();
+ }
+
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/LoggerBridgeTest/CustomSystemClassLoader.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.security.AllPermission;
+import java.security.Permissions;
+import java.security.ProtectionDomain;
+
+
+/**
+ * A custom ClassLoader to load the concrete LoggerFinder class
+ * with all permissions.
+ *
+ * @author danielfuchs
+ */
+public class CustomSystemClassLoader extends ClassLoader {
+
+
+ Class<?> loggerFinderClass = null;
+// Class<?> loggerImplClass = null;
+
+ public CustomSystemClassLoader() {
+ super();
+ }
+ public CustomSystemClassLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ private Class<?> defineFinderClass(String name)
+ throws ClassNotFoundException {
+ final Object obj = getClassLoadingLock(name);
+ synchronized(obj) {
+ if (loggerFinderClass != null) return loggerFinderClass;
+
+ URL url = this.getClass().getProtectionDomain().getCodeSource().getLocation();
+ File file = new File(url.getPath(), name+".class");
+ if (file.canRead()) {
+ try {
+ byte[] b = Files.readAllBytes(file.toPath());
+ Permissions perms = new Permissions();
+ perms.add(new AllPermission());
+ loggerFinderClass = defineClass(
+ name, b, 0, b.length, new ProtectionDomain(
+ this.getClass().getProtectionDomain().getCodeSource(),
+ perms));
+ System.out.println("Loaded " + name);
+ return loggerFinderClass;
+ } catch (Throwable ex) {
+ ex.printStackTrace();
+ throw new ClassNotFoundException(name, ex);
+ }
+ } else {
+ throw new ClassNotFoundException(name,
+ new IOException(file.toPath() + ": can't read"));
+ }
+ }
+ }
+// private Class<?> defineLoggerImplClass(String name)
+// throws ClassNotFoundException {
+// final Object obj = getClassLoadingLock(name);
+// synchronized(obj) {
+// if (loggerImplClass != null) return loggerImplClass;
+//
+// URL url = this.getClass().getProtectionDomain().getCodeSource().getLocation();
+// File file = new File(url.getPath(), name+".class");
+// if (file.canRead()) {
+// try {
+// byte[] b = Files.readAllBytes(file.toPath());
+// Permissions perms = new Permissions();
+// perms.add(new AllPermission());
+// loggerImplClass = defineClass(
+// name, b, 0, b.length, new ProtectionDomain(
+// this.getClass().getProtectionDomain().getCodeSource(),
+// perms));
+// System.out.println("Loaded " + name);
+// return loggerImplClass;
+// } catch (Throwable ex) {
+// ex.printStackTrace();
+// throw new ClassNotFoundException(name, ex);
+// }
+// } else {
+// throw new ClassNotFoundException(name,
+// new IOException(file.toPath() + ": can't read"));
+// }
+// }
+// }
+//
+ @Override
+ public synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ if (name.endsWith("$LogProducerFinder")) {
+ Class<?> c = defineFinderClass(name);
+ if (resolve) {
+ resolveClass(c);
+ }
+ return c;
+ }
+// if (name.endsWith("$LogProducerFinder$LoggerImpl")) {
+// Class<?> c = defineLoggerImplClass(name);
+// if (resolve) {
+// resolveClass(c);
+// }
+// return c;
+// }
+ return super.loadClass(name, resolve);
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+// if (name.endsWith("$LogProducerFinder$LoggerImpl")) {
+// return defineLoggerImplClass(name);
+// }
+ if (name.endsWith("$$LogProducerFinder")) {
+ return defineFinderClass(name);
+ }
+ return super.findClass(name);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/LoggerBridgeTest/LoggerBridgeTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,1087 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.ResourceBundle;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Supplier;
+import java.util.logging.Handler;
+import java.util.logging.LogRecord;
+import java.lang.System.LoggerFinder;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.util.stream.Stream;
+import sun.util.logging.PlatformLogger;
+
+/**
+ * @test
+ * @bug 8140364
+ * @summary JDK implementation specific unit test for JDK internal artifacts.
+ * Tests all bridge methods with the a custom backend whose
+ * loggers implement PlatformLogger.Bridge.
+ * @modules java.base/sun.util.logging java.base/jdk.internal.logger
+ * @build CustomSystemClassLoader LoggerBridgeTest
+ * @run main/othervm -Djava.system.class.loader=CustomSystemClassLoader LoggerBridgeTest NOSECURITY
+ * @run main/othervm -Djava.system.class.loader=CustomSystemClassLoader LoggerBridgeTest NOPERMISSIONS
+ * @run main/othervm -Djava.system.class.loader=CustomSystemClassLoader LoggerBridgeTest WITHPERMISSIONS
+ * @author danielfuchs
+ */
+public class LoggerBridgeTest {
+
+ public static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+
+ final static AtomicLong sequencer = new AtomicLong();
+ final static boolean VERBOSE = false;
+ static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+ static final ThreadLocal<AtomicBoolean> allowAccess = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+ static final ThreadLocal<AtomicBoolean> allowAll = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+
+ public static final Queue<LogEvent> eventQueue = new ArrayBlockingQueue<>(128);
+
+ public static final class LogEvent implements Cloneable {
+
+ public LogEvent() {
+ this(sequencer.getAndIncrement());
+ }
+
+ LogEvent(long sequenceNumber) {
+ this.sequenceNumber = sequenceNumber;
+ }
+
+ long sequenceNumber;
+ boolean isLoggable;
+ String loggerName;
+ sun.util.logging.PlatformLogger.Level level;
+ ResourceBundle bundle;
+ Throwable thrown;
+ Object[] args;
+ String msg;
+ Supplier<String> supplier;
+ String className;
+ String methodName;
+
+ Object[] toArray() {
+ return new Object[] {
+ sequenceNumber,
+ loggerName,
+ level,
+ isLoggable,
+ bundle,
+ msg,
+ supplier,
+ thrown,
+ args,
+ className,
+ methodName,
+ };
+ }
+
+ @Override
+ public String toString() {
+ return Arrays.deepToString(toArray());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof LogEvent
+ && Objects.deepEquals(this.toArray(), ((LogEvent)obj).toArray());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(toArray());
+ }
+
+ public LogEvent cloneWith(long sequenceNumber)
+ throws CloneNotSupportedException {
+ LogEvent cloned = (LogEvent)super.clone();
+ cloned.sequenceNumber = sequenceNumber;
+ return cloned;
+ }
+
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
+ String key, Throwable thrown, Object... params) {
+ return LogEvent.of(sequenceNumber, isLoggable, name,
+ null, null, level, bundle, key,
+ thrown, params);
+ }
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
+ Supplier<String> supplier, Throwable thrown, Object... params) {
+ return LogEvent.of(sequenceNumber, isLoggable, name,
+ null, null, level, bundle, supplier,
+ thrown, params);
+ }
+
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ String className, String methodName,
+ sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
+ String key, Throwable thrown, Object... params) {
+ LogEvent evt = new LogEvent(sequenceNumber);
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = params;
+ evt.bundle = bundle;
+ evt.thrown = thrown;
+ evt.msg = key;
+ evt.isLoggable = isLoggable;
+ evt.className = className;
+ evt.methodName = methodName;
+ return evt;
+ }
+
+ public static LogEvent of(boolean isLoggable, String name,
+ String className, String methodName,
+ sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
+ String key, Throwable thrown, Object... params) {
+ return LogEvent.of(sequencer.getAndIncrement(), isLoggable, name,
+ className, methodName, level, bundle, key, thrown, params);
+ }
+
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ String className, String methodName,
+ sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
+ Supplier<String> supplier, Throwable thrown, Object... params) {
+ LogEvent evt = new LogEvent(sequenceNumber);
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = params;
+ evt.bundle = bundle;
+ evt.thrown = thrown;
+ evt.supplier = supplier;
+ evt.isLoggable = isLoggable;
+ evt.className = className;
+ evt.methodName = methodName;
+ return evt;
+ }
+
+ public static LogEvent of(boolean isLoggable, String name,
+ String className, String methodName,
+ sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
+ Supplier<String> supplier, Throwable thrown, Object... params) {
+ return LogEvent.of(sequencer.getAndIncrement(), isLoggable, name,
+ className, methodName, level, bundle, supplier, thrown, params);
+ }
+
+ }
+ static final Class<?> providerClass;
+ static {
+ try {
+ // Preload classes before the security manager is on.
+ providerClass = ClassLoader.getSystemClassLoader().loadClass("LoggerBridgeTest$LogProducerFinder");
+ ((LoggerFinder)providerClass.newInstance()).getLogger("foo", providerClass);
+ } catch (Exception ex) {
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+ public static class LogProducerFinder extends LoggerFinder {
+ final ConcurrentHashMap<String, LoggerImpl> system = new ConcurrentHashMap<>();
+ final ConcurrentHashMap<String, LoggerImpl> user = new ConcurrentHashMap<>();
+
+ public class LoggerImpl implements Logger, PlatformLogger.Bridge {
+ private final String name;
+ private sun.util.logging.PlatformLogger.Level level = sun.util.logging.PlatformLogger.Level.INFO;
+ private sun.util.logging.PlatformLogger.Level OFF = sun.util.logging.PlatformLogger.Level.OFF;
+ private sun.util.logging.PlatformLogger.Level FINE = sun.util.logging.PlatformLogger.Level.FINE;
+ private sun.util.logging.PlatformLogger.Level FINER = sun.util.logging.PlatformLogger.Level.FINER;
+ private sun.util.logging.PlatformLogger.Level FINEST = sun.util.logging.PlatformLogger.Level.FINEST;
+ private sun.util.logging.PlatformLogger.Level CONFIG = sun.util.logging.PlatformLogger.Level.CONFIG;
+ private sun.util.logging.PlatformLogger.Level INFO = sun.util.logging.PlatformLogger.Level.INFO;
+ private sun.util.logging.PlatformLogger.Level WARNING = sun.util.logging.PlatformLogger.Level.WARNING;
+ private sun.util.logging.PlatformLogger.Level SEVERE = sun.util.logging.PlatformLogger.Level.SEVERE;
+
+ public LoggerImpl(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean isLoggable(Level level) {
+ return this.level != OFF && this.level.intValue() <= level.getSeverity();
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle,
+ String key, Throwable thrown) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle,
+ String format, Object... params) {
+ throw new UnsupportedOperationException();
+ }
+
+ void log(LogEvent event) {
+ eventQueue.add(event);
+ }
+
+ @Override
+ public void log(Level level, Supplier<String> msgSupplier) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void log(Level level, Supplier<String> msgSupplier,
+ Throwable thrown) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void log(sun.util.logging.PlatformLogger.Level level, String msg) {
+ log(LogEvent.of(isLoggable(level), name, null, null,
+ level, null, msg, null, (Object[])null));
+ }
+
+ @Override
+ public void log(sun.util.logging.PlatformLogger.Level level,
+ Supplier<String> msgSupplier) {
+ log(LogEvent.of(isLoggable(level), name, null, null,
+ level, null, msgSupplier, null, (Object[])null));
+ }
+
+ @Override
+ public void log(sun.util.logging.PlatformLogger.Level level, String msg,
+ Object... params) {
+ log(LogEvent.of(isLoggable(level), name, null, null,
+ level, null, msg, null, params));
+ }
+
+ @Override
+ public void log(sun.util.logging.PlatformLogger.Level level, String msg,
+ Throwable thrown) {
+ log(LogEvent.of(isLoggable(level), name, null, null,
+ level, null, msg, thrown, (Object[])null));
+ }
+
+ @Override
+ public void log(sun.util.logging.PlatformLogger.Level level, Throwable thrown,
+ Supplier<String> msgSupplier) {
+ log(LogEvent.of(isLoggable(level), name, null, null,
+ level, null, msgSupplier, thrown, (Object[])null));
+ }
+
+ @Override
+ public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, String msg) {
+ log(LogEvent.of(isLoggable(level), name,
+ sourceClass, sourceMethod,
+ level, null, msg, null, (Object[])null));
+ }
+
+ @Override
+ public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, Supplier<String> msgSupplier) {
+ log(LogEvent.of(isLoggable(level), name,
+ sourceClass, sourceMethod,
+ level, null, msgSupplier, null, (Object[])null));
+ }
+
+ @Override
+ public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, String msg, Object... params) {
+ log(LogEvent.of(isLoggable(level), name,
+ sourceClass, sourceMethod,
+ level, null, msg, null, params));
+ }
+
+ @Override
+ public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, String msg, Throwable thrown) {
+ log(LogEvent.of(isLoggable(level), name,
+ sourceClass, sourceMethod,
+ level, null, msg, thrown, (Object[])null));
+ }
+
+ @Override
+ public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, Throwable thrown,
+ Supplier<String> msgSupplier) {
+ log(LogEvent.of(isLoggable(level), name,
+ sourceClass, sourceMethod,
+ level, null, msgSupplier, thrown, (Object[])null));
+ }
+
+ @Override
+ public void logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, ResourceBundle bundle, String msg,
+ Object... params) {
+ log(LogEvent.of(isLoggable(level), name,
+ sourceClass, sourceMethod,
+ level, bundle, msg, null, params));
+ }
+
+ @Override
+ public void logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
+ String msg, Object... params) {
+ log(LogEvent.of(isLoggable(level), name, null, null,
+ level, bundle, msg, null, params));
+ }
+
+ @Override
+ public void logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, ResourceBundle bundle, String msg,
+ Throwable thrown) {
+ log(LogEvent.of(isLoggable(level), name,
+ sourceClass, sourceMethod,
+ level, bundle, msg, thrown, (Object[])null));
+ }
+
+ @Override
+ public void logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
+ String msg, Throwable thrown) {
+ log(LogEvent.of(isLoggable(level), name, null, null,
+ level, bundle, msg, thrown, (Object[])null));
+ }
+
+ @Override
+ public boolean isLoggable(sun.util.logging.PlatformLogger.Level level) {
+ return this.level != OFF && level.intValue()
+ >= this.level.intValue();
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return this.level != OFF;
+ }
+
+ }
+
+ @Override
+ public Logger getLogger(String name, Class<?> caller) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGERFINDER_PERMISSION);
+ }
+ PrivilegedAction<ClassLoader> pa = () -> caller.getClassLoader();
+ ClassLoader callerLoader = AccessController.doPrivileged(pa);
+ if (callerLoader == null) {
+ return system.computeIfAbsent(name, (n) -> new LoggerImpl(n));
+ } else {
+ return user.computeIfAbsent(name, (n) -> new LoggerImpl(n));
+ }
+ }
+ }
+
+ static final sun.util.logging.PlatformLogger.Level[] julLevels = {
+ sun.util.logging.PlatformLogger.Level.ALL,
+ sun.util.logging.PlatformLogger.Level.FINEST,
+ sun.util.logging.PlatformLogger.Level.FINER,
+ sun.util.logging.PlatformLogger.Level.FINE,
+ sun.util.logging.PlatformLogger.Level.CONFIG,
+ sun.util.logging.PlatformLogger.Level.INFO,
+ sun.util.logging.PlatformLogger.Level.WARNING,
+ sun.util.logging.PlatformLogger.Level.SEVERE,
+ sun.util.logging.PlatformLogger.Level.OFF,
+ };
+
+ public static class MyBundle extends ResourceBundle {
+
+ final ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>();
+
+ @Override
+ protected Object handleGetObject(String key) {
+ if (key.contains(" (translated)")) {
+ throw new RuntimeException("Unexpected key: " + key);
+ }
+ return map.computeIfAbsent(key, k -> k + " (translated)");
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ return Collections.enumeration(map.keySet());
+ }
+
+ }
+
+ public static class MyHandler extends Handler {
+
+ @Override
+ public java.util.logging.Level getLevel() {
+ return java.util.logging.Level.ALL;
+ }
+
+ @Override
+ public void publish(LogRecord record) {
+ eventQueue.add(LogEvent.of(sequencer.getAndIncrement(),
+ true, record.getLoggerName(),
+ record.getSourceClassName(),
+ record.getSourceMethodName(),
+ PlatformLogger.Level.valueOf(record.getLevel().getName()),
+ record.getResourceBundle(), record.getMessage(),
+ record.getThrown(), record.getParameters()));
+ }
+ @Override
+ public void flush() {
+ }
+ @Override
+ public void close() throws SecurityException {
+ }
+
+ }
+
+ public static class MyLoggerBundle extends MyBundle {
+
+ }
+
+ final static Method lazyGetLogger;
+ static {
+ // jdk.internal.logging.LoggerBridge.getLogger(name, caller)
+ try {
+ Class<?> bridgeClass = Class.forName("jdk.internal.logger.LazyLoggers");
+ lazyGetLogger = bridgeClass.getDeclaredMethod("getLogger",
+ String.class, Class.class);
+ lazyGetLogger.setAccessible(true);
+ } catch (Throwable ex) {
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+ static Logger getLogger(LoggerFinder provider, String name, Class<?> caller) {
+ Logger logger;
+ try {
+ logger = Logger.class.cast(lazyGetLogger.invoke(null, name, caller));
+ } catch (Throwable x) {
+ Throwable t = (x instanceof InvocationTargetException) ?
+ ((InvocationTargetException)x).getTargetException() : x;
+ if (t instanceof RuntimeException) {
+ throw (RuntimeException)t;
+ } else if (t instanceof Exception) {
+ throw new RuntimeException(t);
+ } else {
+ throw (Error)t;
+ }
+ }
+ // The method above does not throw exception...
+ // call the provider here to verify that an exception would have
+ // been thrown by the provider.
+ if (logger != null && caller == Thread.class) {
+ Logger log = provider.getLogger(name, caller);
+ }
+ return logger;
+ }
+
+ static Logger getLogger(LoggerFinder provider, String name, ResourceBundle bundle, Class<?> caller) {
+ if (caller.getClassLoader() != null) {
+ return System.getLogger(name,bundle);
+ } else {
+ return provider.getLocalizedLogger(name, bundle, caller);
+ }
+ }
+
+ static PlatformLogger.Bridge convert(Logger logger) {
+ return PlatformLogger.Bridge.convert(logger);
+ }
+
+ static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS};
+
+ static void setSecurityManager() {
+ if (System.getSecurityManager() == null) {
+ Policy.setPolicy(new SimplePolicy(allowControl, allowAccess, allowAll));
+ System.setSecurityManager(new SecurityManager());
+ }
+ }
+
+ public static void main(String[] args) {
+ if (args.length == 0)
+ args = new String[] {
+ //"NOSECURITY",
+ "NOPERMISSIONS",
+ "WITHPERMISSIONS"
+ };
+
+
+ Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> {
+ LoggerFinder provider;
+ switch (testCase) {
+ case NOSECURITY:
+ System.out.println("\n*** Without Security Manager\n");
+ provider = LoggerFinder.getLoggerFinder();
+ test(provider, true);
+ System.out.println("Tetscase count: " + sequencer.get());
+ break;
+ case NOPERMISSIONS:
+ System.out.println("\n*** With Security Manager, without permissions\n");
+ setSecurityManager();
+ try {
+ provider = LoggerFinder.getLoggerFinder();
+ throw new RuntimeException("Expected exception not raised");
+ } catch (AccessControlException x) {
+ if (!LOGGERFINDER_PERMISSION.equals(x.getPermission())) {
+ throw new RuntimeException("Unexpected permission check", x);
+ }
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = LoggerFinder.getLoggerFinder();
+ } finally {
+ allowControl.get().set(control);
+ }
+ }
+ test(provider, false);
+ System.out.println("Tetscase count: " + sequencer.get());
+ break;
+ case WITHPERMISSIONS:
+ System.out.println("\n*** With Security Manager, with control permission\n");
+ setSecurityManager();
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = LoggerFinder.getLoggerFinder();
+ test(provider, true);
+ } finally {
+ allowControl.get().set(control);
+ }
+ break;
+ default:
+ throw new RuntimeException("Unknown test case: " + testCase);
+ }
+ });
+ System.out.println("\nPASSED: Tested " + sequencer.get() + " cases.");
+ }
+
+ public static void test(LoggerFinder provider, boolean hasRequiredPermissions) {
+
+ ResourceBundle loggerBundle = ResourceBundle.getBundle(MyLoggerBundle.class.getName());
+ final Map<Object, String> loggerDescMap = new HashMap<>();
+
+
+ Logger appLogger1 = System.getLogger("foo");
+ loggerDescMap.put(appLogger1, "LogProducer.getApplicationLogger(\"foo\")");
+
+ Logger sysLogger1 = null;
+ try {
+ sysLogger1 = getLogger(provider, "foo", Thread.class);
+ loggerDescMap.put(sysLogger1, "LogProducer.getSystemLogger(\"foo\")");
+ if (!hasRequiredPermissions) {
+ throw new RuntimeException("Managed to obtain a system logger without permission");
+ }
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ System.out.println("Got expected exception for system logger: " + acx);
+ }
+
+
+ Logger appLogger2 =
+ System.getLogger("foo", loggerBundle);
+ loggerDescMap.put(appLogger2, "LogProducer.getApplicationLogger(\"foo\", loggerBundle)");
+
+ Logger sysLogger2 = null;
+ try {
+ sysLogger2 = getLogger(provider, "foo", loggerBundle, Thread.class);
+ loggerDescMap.put(sysLogger2, "provider.getSystemLogger(\"foo\", loggerBundle)");
+ if (!hasRequiredPermissions) {
+ throw new RuntimeException("Managed to obtain a system logger without permission");
+ }
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ System.out.println("Got expected exception for localized system logger: " + acx);
+ }
+ if (hasRequiredPermissions && appLogger2 == sysLogger2) {
+ throw new RuntimeException("identical loggers");
+ }
+ if (appLogger2 == appLogger1) {
+ throw new RuntimeException("identical loggers");
+ }
+ if (hasRequiredPermissions && sysLogger2 == sysLogger1) {
+ throw new RuntimeException("identical loggers");
+ }
+
+
+ final LogProducerFinder.LoggerImpl appSink;
+ final LogProducerFinder.LoggerImpl sysSink;
+ boolean old = allowControl.get().get();
+ allowControl.get().set(true);
+ try {
+ appSink = LogProducerFinder.LoggerImpl.class.cast(
+ provider.getLogger("foo", LoggerBridgeTest.class));
+ sysSink = LogProducerFinder.LoggerImpl.class.cast(
+ provider.getLogger("foo", Thread.class));
+ } finally {
+ allowControl.get().set(old);
+ }
+
+ testLogger(provider, loggerDescMap, "foo", null, convert(appLogger1), appSink);
+ if (hasRequiredPermissions) {
+ testLogger(provider, loggerDescMap, "foo", null, convert(sysLogger1), sysSink);
+ }
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, convert(appLogger2), appSink);
+ if (hasRequiredPermissions) {
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, convert(sysLogger2), sysSink);
+ }
+ }
+
+ public static class Foo {
+
+ }
+
+ static void verbose(String msg) {
+ if (VERBOSE) {
+ System.out.println(msg);
+ }
+ }
+
+ static void checkLogEvent(LoggerFinder provider, String desc,
+ LogEvent expected) {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+
+ static void checkLogEvent(LoggerFinder provider, String desc,
+ LogEvent expected, boolean expectNotNull) {
+ LogEvent actual = eventQueue.poll();
+ if (actual == null && !expectNotNull) return;
+ if (actual != null && !expectNotNull) {
+ throw new RuntimeException("Unexpected log event found for " + desc
+ + "\n\tgot: " + actual);
+ }
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+
+ static void setLevel( LogProducerFinder.LoggerImpl sink,
+ sun.util.logging.PlatformLogger.Level loggerLevel) {
+ sink.level = loggerLevel;
+ }
+
+ // Calls the methods defined on LogProducer and verify the
+ // parameters received by the underlying LogProducerFinder.LoggerImpl
+ // logger.
+ private static void testLogger(LoggerFinder provider,
+ Map<Object, String> loggerDescMap,
+ String name,
+ ResourceBundle loggerBundle,
+ PlatformLogger.Bridge logger,
+ LogProducerFinder.LoggerImpl sink) {
+
+ System.out.println("Testing " + loggerDescMap.get(logger) + "[" + logger + "]");
+ final sun.util.logging.PlatformLogger.Level OFF = sun.util.logging.PlatformLogger.Level.OFF;
+
+ Foo foo = new Foo();
+ String fooMsg = foo.toString();
+ System.out.println("\tlogger.log(messageLevel, fooMsg)");
+ System.out.println("\tlogger.<level>(fooMsg)");
+ for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.log(messageLevel, fooMsg): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, loggerBundle,
+ fooMsg, (Throwable)null, (Object[])null);
+ logger.log(messageLevel, fooMsg);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ Supplier<String> supplier = new Supplier<String>() {
+ @Override
+ public String get() {
+ return this.toString();
+ }
+ };
+ System.out.println("\tlogger.log(messageLevel, supplier)");
+ System.out.println("\tlogger.<level>(supplier)");
+ for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.log(messageLevel, supplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, null,
+ supplier, (Throwable)null, (Object[])null);
+ logger.log(messageLevel, supplier);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ String format = "two params [{1} {2}]";
+ Object arg1 = foo;
+ Object arg2 = fooMsg;
+ System.out.println("\tlogger.log(messageLevel, format, arg1, arg2)");
+ for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.log(messageLevel, format, foo, fooMsg): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, loggerBundle,
+ format, (Throwable)null, arg1, arg2);
+ logger.log(messageLevel, format, arg1, arg2);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ Throwable thrown = new Exception("OK: log me!");
+ System.out.println("\tlogger.log(messageLevel, fooMsg, thrown)");
+ for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.log(messageLevel, fooMsg, thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, loggerBundle,
+ fooMsg, thrown, (Object[])null);
+ logger.log(messageLevel, fooMsg, thrown);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ System.out.println("\tlogger.log(messageLevel, thrown, supplier)");
+ for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.log(messageLevel, thrown, supplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, null,
+ supplier, thrown, (Object[])null);
+ logger.log(messageLevel, thrown, supplier);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ String sourceClass = "blah.Blah";
+ String sourceMethod = "blih";
+ System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, fooMsg)");
+ for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, fooMsg): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, sourceClass, sourceMethod, messageLevel, loggerBundle,
+ fooMsg, (Throwable)null, (Object[])null);
+ logger.logp(messageLevel, sourceClass, sourceMethod, fooMsg);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, supplier)");
+ for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, supplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, sourceClass, sourceMethod, messageLevel, null,
+ supplier, (Throwable)null, (Object[])null);
+ logger.logp(messageLevel, sourceClass, sourceMethod, supplier);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, format, arg1, arg2)");
+ for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, format, arg1, arg2): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, sourceClass, sourceMethod, messageLevel, loggerBundle,
+ format, (Throwable)null, arg1, arg2);
+ logger.logp(messageLevel, sourceClass, sourceMethod, format, arg1, arg2);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, fooMsg, thrown)");
+ for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, fooMsg, thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, sourceClass, sourceMethod, messageLevel, loggerBundle,
+ fooMsg, thrown, (Object[])null);
+ logger.logp(messageLevel, sourceClass, sourceMethod, fooMsg, thrown);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, thrown, supplier)");
+ for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, thrown, supplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, sourceClass, sourceMethod, messageLevel, null,
+ supplier, thrown, (Object[])null);
+ logger.logp(messageLevel, sourceClass, sourceMethod, thrown, supplier);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ ResourceBundle bundle = ResourceBundle.getBundle(MyBundle.class.getName());
+ System.out.println("\tlogger.logrb(messageLevel, bundle, format, arg1, arg2)");
+ for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.logrb(messageLevel, bundle, format, arg1, arg2): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, bundle,
+ format, (Throwable)null, arg1, arg2);
+ logger.logrb(messageLevel, bundle, format, arg1, arg2);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ System.out.println("\tlogger.logrb(messageLevel, bundle, msg, thrown)");
+ for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.logrb(messageLevel, bundle, msg, thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, bundle,
+ fooMsg, thrown, (Object[])null);
+ logger.logrb(messageLevel, bundle, fooMsg, thrown);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ System.out.println("\tlogger.logrb(messageLevel, sourceClass, sourceMethod, bundle, format, arg1, arg2)");
+ for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.logrb(messageLevel, sourceClass, sourceMethod, bundle, format, arg1, arg2): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, sourceClass, sourceMethod, messageLevel, bundle,
+ format, (Throwable)null, arg1, arg2);
+ logger.logrb(messageLevel, sourceClass, sourceMethod, bundle, format, arg1, arg2);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+
+ System.out.println("\tlogger.logrb(messageLevel, sourceClass, sourceMethod, bundle, msg, thrown)");
+ for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ String desc = "logger.logrb(messageLevel, sourceClass, sourceMethod, bundle, msg, thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, sourceClass, sourceMethod, messageLevel, bundle,
+ fooMsg, thrown, (Object[])null);
+ logger.logrb(messageLevel, sourceClass, sourceMethod, bundle, fooMsg, thrown);
+ checkLogEvent(provider, desc, expected);
+ }
+ }
+ }
+
+ final static class PermissionsBuilder {
+ final Permissions perms;
+ public PermissionsBuilder() {
+ this(new Permissions());
+ }
+ public PermissionsBuilder(Permissions perms) {
+ this.perms = perms;
+ }
+ public PermissionsBuilder add(Permission p) {
+ perms.add(p);
+ return this;
+ }
+ public PermissionsBuilder addAll(PermissionCollection col) {
+ if (col != null) {
+ for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
+ perms.add(e.nextElement());
+ }
+ }
+ return this;
+ }
+ public Permissions toPermissions() {
+ final PermissionsBuilder builder = new PermissionsBuilder();
+ builder.addAll(perms);
+ return builder.perms;
+ }
+ }
+
+ public static class SimplePolicy extends Policy {
+ final static RuntimePermission CONTROL = LOGGERFINDER_PERMISSION;
+ final static RuntimePermission ACCESS_LOGGER = new RuntimePermission("accessClassInPackage.jdk.internal.logger");
+ final static RuntimePermission ACCESS_LOGGING = new RuntimePermission("accessClassInPackage.sun.util.logging");
+
+ final Permissions permissions;
+ final Permissions allPermissions;
+ final ThreadLocal<AtomicBoolean> allowControl;
+ final ThreadLocal<AtomicBoolean> allowAccess;
+ final ThreadLocal<AtomicBoolean> allowAll;
+ public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl,
+ ThreadLocal<AtomicBoolean> allowAccess,
+ ThreadLocal<AtomicBoolean> allowAll) {
+ this.allowControl = allowControl;
+ this.allowAccess = allowAccess;
+ this.allowAll = allowAll;
+ permissions = new Permissions();
+ allPermissions = new PermissionsBuilder()
+ .add(new java.security.AllPermission())
+ .toPermissions();
+ }
+
+ Permissions getPermissions() {
+ if (allowControl.get().get() || allowAccess.get().get() || allowAll.get().get()) {
+ PermissionsBuilder builder = new PermissionsBuilder()
+ .addAll(permissions);
+ if (allowControl.get().get()) {
+ builder.add(CONTROL);
+ }
+ if (allowAccess.get().get()) {
+ builder.add(ACCESS_LOGGER);
+ builder.add(ACCESS_LOGGING);
+ }
+ if (allowAll.get().get()) {
+ builder.addAll(allPermissions);
+ }
+ return builder.toPermissions();
+ }
+ return permissions;
+ }
+
+ @Override
+ public boolean implies(ProtectionDomain domain, Permission permission) {
+ return getPermissions().implies(permission);
+ }
+
+ @Override
+ public PermissionCollection getPermissions(CodeSource codesource) {
+ return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
+ }
+
+ @Override
+ public PermissionCollection getPermissions(ProtectionDomain domain) {
+ return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/LoggerBridgeTest/META-INF/services/java.lang.System$LoggerFinder Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,1 @@
+LoggerBridgeTest$LogProducerFinder
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/LoggerFinderLoaderTest/AccessSystemLogger.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.IOException;
+import java.lang.System.Logger;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ResourceBundle;
+
+/**
+ *
+ * @author danielfuchs
+ */
+public final class AccessSystemLogger {
+
+ public AccessSystemLogger() {
+ this(check());
+ }
+
+ private AccessSystemLogger(Void unused) {
+ }
+
+ private static Void check() {
+ if (AccessSystemLogger.class.getClassLoader() != null) {
+ throw new RuntimeException("AccessSystemLogger should be loaded by the null classloader");
+ }
+ return null;
+ }
+
+ public Logger getLogger(String name) {
+ Logger logger = System.getLogger(name);
+ System.out.println("System.getLogger(\"" + name + "\"): " + logger);
+ return logger;
+ }
+
+ public Logger getLogger(String name, ResourceBundle bundle) {
+ Logger logger = System.getLogger(name, bundle);
+ System.out.println("System.getLogger(\"" + name + "\", bundle): " + logger);
+ return logger;
+ }
+
+ static final Class<?>[] toCopy = { AccessSystemLogger.class, CustomSystemClassLoader.class };
+
+ // copy AccessSystemLogger.class to ./boot
+ public static void main(String[] args) throws IOException {
+ Path testDir = Paths.get(System.getProperty("user.dir", "."));
+ Path bootDir = Paths.get(testDir.toString(), "boot");
+ Path classes = Paths.get(System.getProperty("test.classes", "build/classes"));
+ if (Files.notExists(bootDir)) {
+ Files.createDirectory(bootDir);
+ }
+ for (Class<?> c : toCopy) {
+ Path thisClass = Paths.get(classes.toString(),
+ c.getSimpleName()+".class");
+ Path dest = Paths.get(bootDir.toString(),
+ c.getSimpleName()+".class");
+ Files.copy(thisClass, dest, StandardCopyOption.REPLACE_EXISTING);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/LoggerFinderLoaderTest/CustomSystemClassLoader.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.security.AllPermission;
+import java.security.Permissions;
+import java.security.ProtectionDomain;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * A custom ClassLoader to load the concrete LoggerFinder class
+ * with all permissions. The CustomSystemClassLoader class must be
+ * in the BCL, otherwise when system classes - such as
+ * ZoneDateTime try to load their resource bundle a MissingResourceBundle
+ * caused by a SecurityException may be thrown, as the CustomSystemClassLoader
+ * code base will be found in the stack called by doPrivileged.
+ *
+ * @author danielfuchs
+ */
+public class CustomSystemClassLoader extends ClassLoader {
+
+
+ final List<String> finderClassNames =
+ Arrays.asList("LoggerFinderLoaderTest$BaseLoggerFinder",
+ "LoggerFinderLoaderTest$BaseLoggerFinder2");
+ final Map<String, Class<?>> finderClasses = new HashMap<>();
+ Class<?> testLoggerFinderClass;
+
+ public CustomSystemClassLoader() {
+ super();
+ }
+ public CustomSystemClassLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ private Class<?> defineFinderClass(String name)
+ throws ClassNotFoundException {
+ final Object obj = getClassLoadingLock(name);
+ synchronized(obj) {
+ if (finderClasses.get(name) != null) return finderClasses.get(name);
+ if (testLoggerFinderClass == null) {
+ // Hack: we load testLoggerFinderClass to get its code source.
+ // we can't use this.getClass() since we are in the boot.
+ testLoggerFinderClass = super.loadClass("LoggerFinderLoaderTest$TestLoggerFinder");
+ }
+ URL url = testLoggerFinderClass.getProtectionDomain().getCodeSource().getLocation();
+ File file = new File(url.getPath(), name+".class");
+ if (file.canRead()) {
+ try {
+ byte[] b = Files.readAllBytes(file.toPath());
+ Permissions perms = new Permissions();
+ perms.add(new AllPermission());
+ Class<?> finderClass = defineClass(
+ name, b, 0, b.length, new ProtectionDomain(
+ this.getClass().getProtectionDomain().getCodeSource(),
+ perms));
+ System.out.println("Loaded " + name);
+ finderClasses.put(name, finderClass);
+ return finderClass;
+ } catch (Throwable ex) {
+ ex.printStackTrace();
+ throw new ClassNotFoundException(name, ex);
+ }
+ } else {
+ throw new ClassNotFoundException(name,
+ new IOException(file.toPath() + ": can't read"));
+ }
+ }
+ }
+
+ @Override
+ public synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ if (finderClassNames.contains(name)) {
+ Class<?> c = defineFinderClass(name);
+ if (resolve) {
+ resolveClass(c);
+ }
+ return c;
+ }
+ return super.loadClass(name, resolve);
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ if (finderClassNames.contains(name)) {
+ return defineFinderClass(name);
+ }
+ return super.findClass(name);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/LoggerFinderLoaderTest/LoggerFinderLoaderTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,882 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.UncheckedIOException;
+import java.security.AccessControlException;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.stream.Stream;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Supplier;
+import java.lang.System.LoggerFinder;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
+import java.util.concurrent.atomic.AtomicReference;
+import jdk.internal.logger.SimpleConsoleLogger;
+
+/**
+ * @test
+ * @bug 8140364
+ * @summary JDK implementation specific unit test for LoggerFinderLoader.
+ * Tests the behavior of LoggerFinderLoader with respect to the
+ * value of the internal diagnosability switches. Also test the
+ * DefaultLoggerFinder and SimpleConsoleLogger implementation.
+ * @modules java.base/sun.util.logging
+ * java.base/jdk.internal.logger
+ * @build AccessSystemLogger LoggerFinderLoaderTest CustomSystemClassLoader
+ * @run driver AccessSystemLogger
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader LoggerFinderLoaderTest NOSECURITY
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader LoggerFinderLoaderTest NOPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader LoggerFinderLoaderTest WITHPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true LoggerFinderLoaderTest NOSECURITY
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true LoggerFinderLoaderTest NOPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true LoggerFinderLoaderTest WITHPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true -Djdk.logger.finder.error=ERROR LoggerFinderLoaderTest NOSECURITY
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true -Djdk.logger.finder.error=ERROR LoggerFinderLoaderTest NOPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true -Djdk.logger.finder.error=ERROR LoggerFinderLoaderTest WITHPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true -Djdk.logger.finder.error=DEBUG LoggerFinderLoaderTest NOSECURITY
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true -Djdk.logger.finder.error=DEBUG LoggerFinderLoaderTest NOPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true -Djdk.logger.finder.error=DEBUG LoggerFinderLoaderTest WITHPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true -Djdk.logger.finder.error=QUIET LoggerFinderLoaderTest NOSECURITY
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true -Djdk.logger.finder.error=QUIET LoggerFinderLoaderTest NOPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true -Djdk.logger.finder.error=QUIET LoggerFinderLoaderTest WITHPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true LoggerFinderLoaderTest NOSECURITY
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true LoggerFinderLoaderTest NOPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true LoggerFinderLoaderTest WITHPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true -Djdk.logger.finder.error=ERROR LoggerFinderLoaderTest NOSECURITY
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true -Djdk.logger.finder.error=ERROR LoggerFinderLoaderTest NOPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true -Djdk.logger.finder.error=ERROR LoggerFinderLoaderTest WITHPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true -Djdk.logger.finder.error=DEBUG LoggerFinderLoaderTest NOSECURITY
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true -Djdk.logger.finder.error=DEBUG LoggerFinderLoaderTest NOPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true -Djdk.logger.finder.error=DEBUG LoggerFinderLoaderTest WITHPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true -Djdk.logger.finder.error=QUIET LoggerFinderLoaderTest NOSECURITY
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true -Djdk.logger.finder.error=QUIET LoggerFinderLoaderTest NOPERMISSIONS
+ * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true -Djdk.logger.finder.error=QUIET LoggerFinderLoaderTest WITHPERMISSIONS
+ * @author danielfuchs
+ */
+public class LoggerFinderLoaderTest {
+
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+ final static boolean VERBOSE = false;
+ static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+ static final ThreadLocal<AtomicBoolean> allowAccess = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+
+ final static AccessSystemLogger accessSystemLogger = new AccessSystemLogger();
+ static final Class<?>[] providerClass;
+ static {
+ try {
+ providerClass = new Class<?>[] {
+ ClassLoader.getSystemClassLoader().loadClass("LoggerFinderLoaderTest$BaseLoggerFinder"),
+ ClassLoader.getSystemClassLoader().loadClass("LoggerFinderLoaderTest$BaseLoggerFinder2")
+ };
+ } catch (ClassNotFoundException ex) {
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+ /**
+ * What our test provider needs to implement.
+ */
+ public static interface TestLoggerFinder {
+ public final static AtomicBoolean fails = new AtomicBoolean();
+ public final static AtomicReference<String> conf = new AtomicReference<>("");
+ public final static AtomicLong sequencer = new AtomicLong();
+ public final ConcurrentHashMap<String, LoggerImpl> system = new ConcurrentHashMap<>();
+ public final ConcurrentHashMap<String, LoggerImpl> user = new ConcurrentHashMap<>();
+
+ public class LoggerImpl implements System.Logger {
+ final String name;
+ final Logger logger;
+
+ public LoggerImpl(String name, Logger logger) {
+ this.name = name;
+ this.logger = logger;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean isLoggable(Logger.Level level) {
+ return logger.isLoggable(level);
+ }
+
+ @Override
+ public void log(Logger.Level level, ResourceBundle bundle, String key, Throwable thrown) {
+ logger.log(level, bundle, key, thrown);
+ }
+
+ @Override
+ public void log(Logger.Level level, ResourceBundle bundle, String format, Object... params) {
+ logger.log(level, bundle, format, params);
+ }
+
+ }
+
+ public Logger getLogger(String name, Class<?> caller);
+ public Logger getLocalizedLogger(String name, ResourceBundle bundle, Class<?> caller);
+ }
+
+ public static class BaseLoggerFinder extends LoggerFinder implements TestLoggerFinder {
+
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+ public BaseLoggerFinder() {
+ if (fails.get()) {
+ throw new RuntimeException("Simulate exception while loading provider");
+ }
+ }
+
+ System.Logger createSimpleLogger(String name) {
+ PrivilegedAction<System.Logger> pa = () -> SimpleConsoleLogger.makeSimpleLogger(name, false);
+ return AccessController.doPrivileged(pa);
+ }
+
+
+ @Override
+ public Logger getLogger(String name, Class<?> caller) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGERFINDER_PERMISSION);
+ }
+ PrivilegedAction<ClassLoader> pa = () -> caller.getClassLoader();
+ ClassLoader callerLoader = AccessController.doPrivileged(pa);
+ if (callerLoader == null) {
+ return system.computeIfAbsent(name, (n) -> new LoggerImpl(n, createSimpleLogger(name)));
+ } else {
+ return user.computeIfAbsent(name, (n) -> new LoggerImpl(n, createSimpleLogger(name)));
+ }
+ }
+ }
+
+ public static class BaseLoggerFinder2 extends LoggerFinder implements TestLoggerFinder {
+
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+ public BaseLoggerFinder2() {
+ throw new ServiceConfigurationError("Should not come here");
+ }
+ @Override
+ public Logger getLogger(String name, Class<?> caller) {
+ throw new ServiceConfigurationError("Should not come here");
+ }
+ }
+
+ public static class MyBundle extends ResourceBundle {
+
+ final ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>();
+
+ @Override
+ protected Object handleGetObject(String key) {
+ if (key.contains(" (translated)")) {
+ throw new RuntimeException("Unexpected key: " + key);
+ }
+ return map.computeIfAbsent(key, k -> k.toUpperCase(Locale.ROOT) + " (translated)");
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ return Collections.enumeration(map.keySet());
+ }
+
+ }
+ public static class MyLoggerBundle extends MyBundle {
+
+ }
+
+ static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS};
+
+ static void setSecurityManager() {
+ if (System.getSecurityManager() == null) {
+ Policy.setPolicy(new SimplePolicy(allowControl, allowAccess));
+ System.setSecurityManager(new SecurityManager());
+ }
+ }
+
+ static LoggerFinder getLoggerFinder(Class<?> expectedClass,
+ String errorPolicy, boolean singleton) {
+ LoggerFinder provider = null;
+ try {
+ TestLoggerFinder.sequencer.incrementAndGet();
+ provider = LoggerFinder.getLoggerFinder();
+ if (TestLoggerFinder.fails.get() || singleton) {
+ if ("ERROR".equals(errorPolicy.toUpperCase(Locale.ROOT))) {
+ throw new RuntimeException("Expected exception not thrown");
+ } else if ("WARNING".equals(errorPolicy.toUpperCase(Locale.ROOT))) {
+ String warning = ErrorStream.errorStream.peek();
+ if (!warning.contains("WARNING: Failed to instantiate LoggerFinder provider; Using default.")) {
+ throw new RuntimeException("Expected message not found. Error stream contained: " + warning);
+ }
+ } else if ("DEBUG".equals(errorPolicy.toUpperCase(Locale.ROOT))) {
+ String warning = ErrorStream.errorStream.peek();
+ if (!warning.contains("WARNING: Failed to instantiate LoggerFinder provider; Using default.")) {
+ throw new RuntimeException("Expected message not found. Error stream contained: " + warning);
+ }
+ if (!warning.contains("WARNING: Exception raised trying to instantiate LoggerFinder")) {
+ throw new RuntimeException("Expected message not found. Error stream contained: " + warning);
+ }
+ if (TestLoggerFinder.fails.get()) {
+ if (!warning.contains("java.util.ServiceConfigurationError: java.lang.System$LoggerFinder: Provider LoggerFinderLoaderTest$BaseLoggerFinder could not be instantiated")) {
+ throw new RuntimeException("Expected message not found. Error stream contained: " + warning);
+ }
+ } else if (singleton) {
+ if (!warning.contains("java.util.ServiceConfigurationError: More than on LoggerFinder implementation")) {
+ throw new RuntimeException("Expected message not found. Error stream contained: " + warning);
+ }
+ }
+ } else if ("QUIET".equals(errorPolicy.toUpperCase(Locale.ROOT))) {
+ if (!ErrorStream.errorStream.peek().isEmpty()) {
+ throw new RuntimeException("Unexpected error message found: "
+ + ErrorStream.errorStream.peek());
+ }
+ }
+ }
+ } catch(AccessControlException a) {
+ throw a;
+ } catch(Throwable t) {
+ if (TestLoggerFinder.fails.get() || singleton) {
+ // must check System.err
+ if ("ERROR".equals(errorPolicy.toUpperCase(Locale.ROOT))) {
+ provider = LoggerFinder.getLoggerFinder();
+ } else {
+ Throwable orig = t.getCause();
+ while (orig != null && orig.getCause() != null) orig = orig.getCause();
+ if (orig != null) orig.printStackTrace(ErrorStream.err);
+ throw new RuntimeException("Unexpected exception: " + t, t);
+ }
+ } else {
+ throw new RuntimeException("Unexpected exception: " + t, t);
+ }
+ }
+ expectedClass.cast(provider);
+ ErrorStream.errorStream.store();
+ System.out.println("*** Actual LoggerFinder class is: " + provider.getClass().getName());
+ return provider;
+ }
+
+
+ static class ErrorStream extends PrintStream {
+
+ static AtomicBoolean forward = new AtomicBoolean();
+ ByteArrayOutputStream out;
+ String saved = "";
+ public ErrorStream(ByteArrayOutputStream out) {
+ super(out);
+ this.out = out;
+ }
+
+ @Override
+ public void write(int b) {
+ super.write(b);
+ if (forward.get()) err.write(b);
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ super.write(b);
+ if (forward.get()) err.write(b);
+ }
+
+ @Override
+ public void write(byte[] buf, int off, int len) {
+ super.write(buf, off, len);
+ if (forward.get()) err.write(buf, off, len);
+ }
+
+ public String peek() {
+ flush();
+ return out.toString();
+ }
+
+ public String drain() {
+ flush();
+ String res = out.toString();
+ out.reset();
+ return res;
+ }
+
+ public void store() {
+ flush();
+ saved = out.toString();
+ out.reset();
+ }
+
+ public void restore() {
+ out.reset();
+ try {
+ out.write(saved.getBytes());
+ } catch(IOException io) {
+ throw new UncheckedIOException(io);
+ }
+ }
+
+ static final PrintStream err = System.err;
+ static final ErrorStream errorStream = new ErrorStream(new ByteArrayOutputStream());
+ }
+
+ private static StringBuilder appendProperty(StringBuilder b, String name) {
+ String value = System.getProperty(name);
+ if (value == null) return b;
+ return b.append(name).append("=").append(value).append('\n');
+ }
+
+ public static void main(String[] args) {
+ if (args.length == 0) {
+ args = new String[] {
+ "NOSECURITY",
+ "NOPERMISSIONS",
+ "WITHPERMISSIONS"
+ };
+ }
+ Locale.setDefault(Locale.ENGLISH);
+ System.setErr(ErrorStream.errorStream);
+ System.setProperty("jdk.logger.packages", TestLoggerFinder.LoggerImpl.class.getName());
+ //System.setProperty("jdk.logger.finder.error", "ERROR");
+ //System.setProperty("jdk.logger.finder.singleton", "true");
+ //System.setProperty("test.fails", "true");
+ TestLoggerFinder.fails.set(Boolean.getBoolean("test.fails"));
+ StringBuilder c = new StringBuilder();
+ appendProperty(c, "jdk.logger.packages");
+ appendProperty(c, "jdk.logger.finder.error");
+ appendProperty(c, "jdk.logger.finder.singleton");
+ appendProperty(c, "test.fails");
+ TestLoggerFinder.conf.set(c.toString());
+ try {
+ test(args);
+ } finally {
+ try {
+ System.setErr(ErrorStream.err);
+ } catch (Error | RuntimeException x) {
+ x.printStackTrace(ErrorStream.err);
+ }
+ }
+ }
+
+
+ public static void test(String[] args) {
+
+ final String errorPolicy = System.getProperty("jdk.logger.finder.error", "WARNING");
+ final Boolean ensureSingleton = Boolean.getBoolean("jdk.logger.finder.singleton");
+
+ final Class<?> expectedClass =
+ TestLoggerFinder.fails.get() || ensureSingleton
+ ? jdk.internal.logger.DefaultLoggerFinder.class
+ : TestLoggerFinder.class;
+
+ System.out.println("Declared provider class: " + providerClass[0]
+ + "[" + providerClass[0].getClassLoader() + "]");
+
+ if (!TestLoggerFinder.fails.get()) {
+ ServiceLoader<LoggerFinder> serviceLoader =
+ ServiceLoader.load(LoggerFinder.class, ClassLoader.getSystemClassLoader());
+ Iterator<LoggerFinder> iterator = serviceLoader.iterator();
+ Object firstProvider = iterator.next();
+ if (!firstProvider.getClass().getName().equals("LoggerFinderLoaderTest$BaseLoggerFinder")) {
+ throw new RuntimeException("Unexpected provider: " + firstProvider.getClass().getName());
+ }
+ if (!iterator.hasNext()) {
+ throw new RuntimeException("Expected two providers");
+ }
+ }
+
+ Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> {
+ LoggerFinder provider;
+ ErrorStream.errorStream.restore();
+ switch (testCase) {
+ case NOSECURITY:
+ System.out.println("\n*** Without Security Manager\n");
+ System.out.println(TestLoggerFinder.conf.get());
+ provider = getLoggerFinder(expectedClass, errorPolicy, ensureSingleton);
+ test(provider, true);
+ System.out.println("Tetscase count: " + TestLoggerFinder.sequencer.get());
+ break;
+ case NOPERMISSIONS:
+ System.out.println("\n*** With Security Manager, without permissions\n");
+ System.out.println(TestLoggerFinder.conf.get());
+ setSecurityManager();
+ try {
+ provider = getLoggerFinder(expectedClass, errorPolicy, ensureSingleton);
+ throw new RuntimeException("Expected exception not raised");
+ } catch (AccessControlException x) {
+ if (!LOGGERFINDER_PERMISSION.equals(x.getPermission())) {
+ throw new RuntimeException("Unexpected permission check", x);
+ }
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = getLoggerFinder(expectedClass, errorPolicy, ensureSingleton);
+ } finally {
+ allowControl.get().set(control);
+ }
+ }
+ test(provider, false);
+ System.out.println("Tetscase count: " + TestLoggerFinder.sequencer.get());
+ break;
+ case WITHPERMISSIONS:
+ System.out.println("\n*** With Security Manager, with control permission\n");
+ System.out.println(TestLoggerFinder.conf.get());
+ setSecurityManager();
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = getLoggerFinder(expectedClass, errorPolicy, ensureSingleton);
+ test(provider, true);
+ } finally {
+ allowControl.get().set(control);
+ }
+ break;
+ default:
+ throw new RuntimeException("Unknown test case: " + testCase);
+ }
+ });
+ System.out.println("\nPASSED: Tested " + TestLoggerFinder.sequencer.get() + " cases.");
+ }
+
+ public static void test(LoggerFinder provider, boolean hasRequiredPermissions) {
+
+ ResourceBundle loggerBundle = ResourceBundle.getBundle(MyLoggerBundle.class.getName());
+ final Map<Logger, String> loggerDescMap = new HashMap<>();
+
+ System.Logger sysLogger = accessSystemLogger.getLogger("foo");
+ loggerDescMap.put(sysLogger, "accessSystemLogger.getLogger(\"foo\")");
+ System.Logger localizedSysLogger = accessSystemLogger.getLogger("fox", loggerBundle);
+ loggerDescMap.put(localizedSysLogger, "accessSystemLogger.getLogger(\"fox\", loggerBundle)");
+ System.Logger appLogger = System.getLogger("bar");
+ loggerDescMap.put(appLogger,"System.getLogger(\"bar\")");
+ System.Logger localizedAppLogger = System.getLogger("baz", loggerBundle);
+ loggerDescMap.put(localizedAppLogger,"System.getLogger(\"baz\", loggerBundle)");
+
+ testLogger(provider, loggerDescMap, "foo", null, sysLogger);
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, localizedSysLogger);
+ testLogger(provider, loggerDescMap, "foo", null, appLogger);
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, localizedAppLogger);
+ }
+
+ public static class Foo {
+
+ }
+
+ static void verbose(String msg) {
+ if (VERBOSE) {
+ System.out.println(msg);
+ }
+ }
+
+ // Calls the 8 methods defined on Logger and verify the
+ // parameters received by the underlying TestProvider.LoggerImpl
+ // logger.
+ private static void testLogger(LoggerFinder provider,
+ Map<Logger, String> loggerDescMap,
+ String name,
+ ResourceBundle loggerBundle,
+ Logger logger) {
+
+ System.out.println("Testing " + loggerDescMap.get(logger) + " [" + logger +"]");
+ AtomicLong sequencer = TestLoggerFinder.sequencer;
+
+ Foo foo = new Foo();
+ String fooMsg = foo.toString();
+ for (Level loggerLevel : EnumSet.of(Level.INFO)) {
+ for (Level messageLevel : Level.values()) {
+ ErrorStream.errorStream.drain();
+ String desc = "logger.log(messageLevel, foo): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ sequencer.incrementAndGet();
+ logger.log(messageLevel, foo);
+ if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (!ErrorStream.errorStream.peek().isEmpty()) {
+ throw new RuntimeException("unexpected event in queue for "
+ + desc +": " + "\n\t" + ErrorStream.errorStream.drain());
+ }
+ } else {
+ String logged = ErrorStream.errorStream.drain();
+ if (!logged.contains("LoggerFinderLoaderTest testLogger")
+ || !logged.contains(messageLevel.getName() + ": " + fooMsg)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected:" + "\n<<<<\n"
+ + "[date] LoggerFinderLoaderTest testLogger\n"
+ + messageLevel.getName() + " " + fooMsg
+ + "\n>>>>"
+ + "\n\t actual:"
+ + "\n<<<<\n" + logged + ">>>>\n");
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n<<<<\n" + logged + ">>>>\n");
+ }
+ }
+ }
+ }
+
+ String msg = "blah";
+ for (Level loggerLevel : EnumSet.of(Level.INFO)) {
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, \"blah\"): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ sequencer.incrementAndGet();
+ logger.log(messageLevel, msg);
+ if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (!ErrorStream.errorStream.peek().isEmpty()) {
+ throw new RuntimeException("unexpected event in queue for "
+ + desc +": " + "\n\t" + ErrorStream.errorStream.drain());
+ }
+ } else {
+ String logged = ErrorStream.errorStream.drain();
+ String msgText = loggerBundle == null ? msg : loggerBundle.getString(msg);
+ if (!logged.contains("LoggerFinderLoaderTest testLogger")
+ || !logged.contains(messageLevel.getName() + ": " + msgText)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected:" + "\n<<<<\n"
+ + "[date] LoggerFinderLoaderTest testLogger\n"
+ + messageLevel.getName() + " " + msgText
+ + "\n>>>>"
+ + "\n\t actual:"
+ + "\n<<<<\n" + logged + ">>>>\n");
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n<<<<\n" + logged + ">>>>\n");
+ }
+ }
+ }
+ }
+
+ Supplier<String> fooSupplier = new Supplier<String>() {
+ @Override
+ public String get() {
+ return this.toString();
+ }
+ };
+
+ for (Level loggerLevel : EnumSet.of(Level.INFO)) {
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, fooSupplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ sequencer.incrementAndGet();
+ logger.log(messageLevel, fooSupplier);
+ if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (!ErrorStream.errorStream.peek().isEmpty()) {
+ throw new RuntimeException("unexpected event in queue for "
+ + desc +": " + "\n\t" + ErrorStream.errorStream.drain());
+ }
+ } else {
+ String logged = ErrorStream.errorStream.drain();
+ if (!logged.contains("LoggerFinderLoaderTest testLogger")
+ || !logged.contains(messageLevel.getName() + ": " + fooSupplier.get())) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected:" + "\n<<<<\n"
+ + "[date] LoggerFinderLoaderTest testLogger\n"
+ + messageLevel.getName() + " " + fooSupplier.get()
+ + "\n>>>>"
+ + "\n\t actual:"
+ + "\n<<<<\n" + logged + ">>>>\n");
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n<<<<\n" + logged + ">>>>\n");
+ }
+ }
+ }
+ }
+
+
+ String format = "two params [{1} {2}]";
+ Object arg1 = foo;
+ Object arg2 = msg;
+ for (Level loggerLevel : EnumSet.of(Level.INFO)) {
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, format, params...): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ sequencer.incrementAndGet();
+ logger.log(messageLevel, format, foo, msg);
+ if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (!ErrorStream.errorStream.peek().isEmpty()) {
+ throw new RuntimeException("unexpected event in queue for "
+ + desc +": " + "\n\t" + ErrorStream.errorStream.drain());
+ }
+ } else {
+ String logged = ErrorStream.errorStream.drain();
+ String msgFormat = loggerBundle == null ? format : loggerBundle.getString(format);
+ String text = java.text.MessageFormat.format(msgFormat, foo, msg);
+ if (!logged.contains("LoggerFinderLoaderTest testLogger")
+ || !logged.contains(messageLevel.getName() + ": " + text)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected:" + "\n<<<<\n"
+ + "[date] LoggerFinderLoaderTest testLogger\n"
+ + messageLevel.getName() + " " + text
+ + "\n>>>>"
+ + "\n\t actual:"
+ + "\n<<<<\n" + logged + ">>>>\n");
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n<<<<\n" + logged + ">>>>\n");
+ }
+ }
+ }
+ }
+
+ Throwable thrown = new Exception("OK: log me!");
+ for (Level loggerLevel : EnumSet.of(Level.INFO)) {
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, \"blah\", thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ sequencer.incrementAndGet();
+ logger.log(messageLevel, msg, thrown);
+ if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (!ErrorStream.errorStream.peek().isEmpty()) {
+ throw new RuntimeException("unexpected event in queue for "
+ + desc +": " + "\n\t" + ErrorStream.errorStream.drain());
+ }
+ } else {
+ String logged = ErrorStream.errorStream.drain();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ thrown.printStackTrace(new PrintStream(baos));
+ String text = baos.toString();
+ String msgText = loggerBundle == null ? msg : loggerBundle.getString(msg);
+ if (!logged.contains("LoggerFinderLoaderTest testLogger")
+ || !logged.contains(messageLevel.getName() + ": " + msgText)
+ || !logged.contains(text)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected:" + "\n<<<<\n"
+ + "[date] LoggerFinderLoaderTest testLogger\n"
+ + messageLevel.getName() + " " + msgText +"\n"
+ + text
+ + ">>>>"
+ + "\n\t actual:"
+ + "\n<<<<\n" + logged + ">>>>\n");
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n<<<<\n" + logged + ">>>>\n");
+ }
+ }
+ }
+ }
+
+
+ for (Level loggerLevel : EnumSet.of(Level.INFO)) {
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, thrown, fooSupplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ sequencer.incrementAndGet();
+ logger.log(messageLevel, fooSupplier, thrown);
+ if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (!ErrorStream.errorStream.peek().isEmpty()) {
+ throw new RuntimeException("unexpected event in queue for "
+ + desc +": " + "\n\t" + ErrorStream.errorStream.drain());
+ }
+ } else {
+ String logged = ErrorStream.errorStream.drain();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ thrown.printStackTrace(new PrintStream(baos));
+ String text = baos.toString();
+ if (!logged.contains("LoggerFinderLoaderTest testLogger")
+ || !logged.contains(messageLevel.getName() + ": " + fooSupplier.get())
+ || !logged.contains(text)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected:" + "\n<<<<\n"
+ + "[date] LoggerFinderLoaderTest testLogger\n"
+ + messageLevel.getName() + " " + fooSupplier.get() +"\n"
+ + text
+ + ">>>>"
+ + "\n\t actual:"
+ + "\n<<<<\n" + logged + ">>>>\n");
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n<<<<\n" + logged + ">>>>\n");
+ }
+ }
+ }
+ }
+
+ ResourceBundle bundle = ResourceBundle.getBundle(MyBundle.class.getName());
+ for (Level loggerLevel : EnumSet.of(Level.INFO)) {
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, bundle, format, params...): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ sequencer.incrementAndGet();
+ logger.log(messageLevel, bundle, format, foo, msg);
+ if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (!ErrorStream.errorStream.peek().isEmpty()) {
+ throw new RuntimeException("unexpected event in queue for "
+ + desc +": " + "\n\t" + ErrorStream.errorStream.drain());
+ }
+ } else {
+ String logged = ErrorStream.errorStream.drain();
+ String text = java.text.MessageFormat.format(bundle.getString(format), foo, msg);
+ if (!logged.contains("LoggerFinderLoaderTest testLogger")
+ || !logged.contains(messageLevel.getName() + ": " + text)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected:" + "\n<<<<\n"
+ + "[date] LoggerFinderLoaderTest testLogger\n"
+ + messageLevel.getName() + " " + text
+ + "\n>>>>"
+ + "\n\t actual:"
+ + "\n<<<<\n" + logged + ">>>>\n");
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n<<<<\n" + logged + ">>>>\n");
+ }
+ }
+ }
+ }
+
+ for (Level loggerLevel : EnumSet.of(Level.INFO)) {
+ for (Level messageLevel : Level.values()) {
+ String desc = "logger.log(messageLevel, bundle, \"blah\", thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ sequencer.incrementAndGet();
+ logger.log(messageLevel, bundle, msg, thrown);
+ if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
+ if (!ErrorStream.errorStream.peek().isEmpty()) {
+ throw new RuntimeException("unexpected event in queue for "
+ + desc +": " + "\n\t" + ErrorStream.errorStream.drain());
+ }
+ } else {
+ String logged = ErrorStream.errorStream.drain();
+ String textMsg = bundle.getString(msg);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ thrown.printStackTrace(new PrintStream(baos));
+ String text = baos.toString();
+ if (!logged.contains("LoggerFinderLoaderTest testLogger")
+ || !logged.contains(messageLevel.getName() + ": " + textMsg)
+ || !logged.contains(text)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected:" + "\n<<<<\n"
+ + "[date] LoggerFinderLoaderTest testLogger\n"
+ + messageLevel.getName() + " " + textMsg +"\n"
+ + text
+ + ">>>>"
+ + "\n\t actual:"
+ + "\n<<<<\n" + logged + ">>>>\n");
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n<<<<\n" + logged + ">>>>\n");
+ }
+ }
+ }
+ }
+
+ }
+
+ final static class PermissionsBuilder {
+ final Permissions perms;
+ public PermissionsBuilder() {
+ this(new Permissions());
+ }
+ public PermissionsBuilder(Permissions perms) {
+ this.perms = perms;
+ }
+ public PermissionsBuilder add(Permission p) {
+ perms.add(p);
+ return this;
+ }
+ public PermissionsBuilder addAll(PermissionCollection col) {
+ if (col != null) {
+ for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
+ perms.add(e.nextElement());
+ }
+ }
+ return this;
+ }
+ public Permissions toPermissions() {
+ final PermissionsBuilder builder = new PermissionsBuilder();
+ builder.addAll(perms);
+ return builder.perms;
+ }
+ }
+
+ public static class SimplePolicy extends Policy {
+ final static RuntimePermission CONTROL = LOGGERFINDER_PERMISSION;
+ final static RuntimePermission ACCESS = new RuntimePermission("accessClassInPackage.jdk.internal.logger");
+
+ final Permissions permissions;
+ final ThreadLocal<AtomicBoolean> allowControl;
+ final ThreadLocal<AtomicBoolean> allowAccess;
+ public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl, ThreadLocal<AtomicBoolean> allowAccess) {
+ this.allowControl = allowControl;
+ this.allowAccess = allowAccess;
+ permissions = new Permissions();
+ permissions.add(new RuntimePermission("setIO"));
+ }
+
+ Permissions getPermissions() {
+ if (allowControl.get().get() || allowAccess.get().get()) {
+ PermissionsBuilder builder = new PermissionsBuilder()
+ .addAll(permissions);
+ if (allowControl.get().get()) {
+ builder.add(CONTROL);
+ }
+ if (allowAccess.get().get()) {
+ builder.add(ACCESS);
+ }
+ return builder.toPermissions();
+ }
+ return permissions;
+ }
+
+ @Override
+ public boolean implies(ProtectionDomain domain, Permission permission) {
+ return getPermissions().implies(permission);
+ }
+
+ @Override
+ public PermissionCollection getPermissions(CodeSource codesource) {
+ return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
+ }
+
+ @Override
+ public PermissionCollection getPermissions(ProtectionDomain domain) {
+ return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/LoggerFinderLoaderTest/META-INF/services/java.lang.System$LoggerFinder Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,3 @@
+LoggerFinderLoaderTest$BaseLoggerFinder
+LoggerFinderLoaderTest$BaseLoggerFinder2
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/PlatformLoggerBridgeTest/CustomSystemClassLoader.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.security.AllPermission;
+import java.security.Permissions;
+import java.security.ProtectionDomain;
+
+
+/**
+ * A custom ClassLoader to load the concrete LoggerFinder class
+ * with all permissions.
+ *
+ * @author danielfuchs
+ */
+public class CustomSystemClassLoader extends ClassLoader {
+
+
+ Class<?> loggerFinderClass = null;
+
+ public CustomSystemClassLoader() {
+ super();
+ }
+ public CustomSystemClassLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ private Class<?> defineFinderClass(String name)
+ throws ClassNotFoundException {
+ final Object obj = getClassLoadingLock(name);
+ synchronized(obj) {
+ if (loggerFinderClass != null) return loggerFinderClass;
+
+ URL url = this.getClass().getProtectionDomain().getCodeSource().getLocation();
+ File file = new File(url.getPath(), name+".class");
+ if (file.canRead()) {
+ try {
+ byte[] b = Files.readAllBytes(file.toPath());
+ Permissions perms = new Permissions();
+ perms.add(new AllPermission());
+ loggerFinderClass = defineClass(
+ name, b, 0, b.length, new ProtectionDomain(
+ this.getClass().getProtectionDomain().getCodeSource(),
+ perms));
+ System.out.println("Loaded " + name);
+ return loggerFinderClass;
+ } catch (Throwable ex) {
+ ex.printStackTrace();
+ throw new ClassNotFoundException(name, ex);
+ }
+ } else {
+ throw new ClassNotFoundException(name,
+ new IOException(file.toPath() + ": can't read"));
+ }
+ }
+ }
+
+ @Override
+ public synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ if (name.endsWith("$LogProducerFinder")) {
+ Class<?> c = defineFinderClass(name);
+ if (resolve) {
+ resolveClass(c);
+ }
+ return c;
+ }
+ return super.loadClass(name, resolve);
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ if (name.endsWith("$$LogProducerFinder")) {
+ return defineFinderClass(name);
+ }
+ return super.findClass(name);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/PlatformLoggerBridgeTest/META-INF/services/java.lang.System$LoggerFinder Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,1 @@
+PlatformLoggerBridgeTest$LogProducerFinder
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/PlatformLoggerBridgeTest/PlatformLoggerBridgeTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,876 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.ResourceBundle;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Supplier;
+import java.util.logging.Handler;
+import java.util.logging.LogRecord;
+import java.lang.System.LoggerFinder;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.util.stream.Stream;
+import sun.util.logging.PlatformLogger;
+
+/**
+ * @test
+ * @bug 8140364
+ * @summary JDK implementation specific unit test for JDK internal artifacts.
+ * Tests all bridge methods from PlatformLogger with the a custom
+ * backend whose loggers implement PlatformLogger.Bridge.
+ * @modules java.base/sun.util.logging
+ * @build CustomSystemClassLoader PlatformLoggerBridgeTest
+ * @run main/othervm -Djava.system.class.loader=CustomSystemClassLoader PlatformLoggerBridgeTest NOSECURITY
+ * @run main/othervm -Djava.system.class.loader=CustomSystemClassLoader PlatformLoggerBridgeTest NOPERMISSIONS
+ * @run main/othervm -Djava.system.class.loader=CustomSystemClassLoader PlatformLoggerBridgeTest WITHPERMISSIONS
+ * @author danielfuchs
+ */
+public class PlatformLoggerBridgeTest {
+
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+ final static AtomicLong sequencer = new AtomicLong();
+ final static boolean VERBOSE = false;
+ static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+ static final ThreadLocal<AtomicBoolean> allowAccess = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+ static final ThreadLocal<AtomicBoolean> allowAll = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+
+ static final Class<?> providerClass;
+ static {
+ try {
+ // Preload classes before the security manager is on.
+ providerClass = ClassLoader.getSystemClassLoader().loadClass("PlatformLoggerBridgeTest$LogProducerFinder");
+ ((LoggerFinder)providerClass.newInstance()).getLogger("foo", providerClass);
+ } catch (Exception ex) {
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+ public static final Queue<LogEvent> eventQueue = new ArrayBlockingQueue<>(128);
+
+ public static final class LogEvent implements Cloneable {
+
+ public LogEvent() {
+ this(sequencer.getAndIncrement());
+ }
+
+ LogEvent(long sequenceNumber) {
+ this.sequenceNumber = sequenceNumber;
+ }
+
+ long sequenceNumber;
+ boolean isLoggable;
+ String loggerName;
+ sun.util.logging.PlatformLogger.Level level;
+ ResourceBundle bundle;
+ Throwable thrown;
+ Object[] args;
+ String msg;
+ Supplier<String> supplier;
+ String className;
+ String methodName;
+
+ Object[] toArray() {
+ return new Object[] {
+ sequenceNumber,
+ loggerName,
+ level,
+ isLoggable,
+ bundle,
+ msg,
+ supplier,
+ thrown,
+ args,
+ className,
+ methodName,
+ };
+ }
+
+ @Override
+ public String toString() {
+ return Arrays.deepToString(toArray());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof LogEvent
+ && Objects.deepEquals(this.toArray(), ((LogEvent)obj).toArray());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(toArray());
+ }
+
+ public LogEvent cloneWith(long sequenceNumber)
+ throws CloneNotSupportedException {
+ LogEvent cloned = (LogEvent)super.clone();
+ cloned.sequenceNumber = sequenceNumber;
+ return cloned;
+ }
+
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
+ String key, Throwable thrown, Object... params) {
+ return LogEvent.of(sequenceNumber, isLoggable, name,
+ null, null, level, bundle, key,
+ thrown, params);
+ }
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
+ Supplier<String> supplier, Throwable thrown, Object... params) {
+ return LogEvent.of(sequenceNumber, isLoggable, name,
+ null, null, level, bundle, supplier,
+ thrown, params);
+ }
+
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ String className, String methodName,
+ sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
+ String key, Throwable thrown, Object... params) {
+ LogEvent evt = new LogEvent(sequenceNumber);
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = params;
+ evt.bundle = bundle;
+ evt.thrown = thrown;
+ evt.msg = key;
+ evt.isLoggable = isLoggable;
+ evt.className = className;
+ evt.methodName = methodName;
+ return evt;
+ }
+
+ public static LogEvent of(boolean isLoggable, String name,
+ String className, String methodName,
+ sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
+ String key, Throwable thrown, Object... params) {
+ return LogEvent.of(sequencer.getAndIncrement(), isLoggable, name,
+ className, methodName, level, bundle, key, thrown, params);
+ }
+
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ String className, String methodName,
+ sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
+ Supplier<String> supplier, Throwable thrown, Object... params) {
+ LogEvent evt = new LogEvent(sequenceNumber);
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = params;
+ evt.bundle = bundle;
+ evt.thrown = thrown;
+ evt.supplier = supplier;
+ evt.isLoggable = isLoggable;
+ evt.className = className;
+ evt.methodName = methodName;
+ return evt;
+ }
+
+ public static LogEvent of(boolean isLoggable, String name,
+ String className, String methodName,
+ sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
+ Supplier<String> supplier, Throwable thrown, Object... params) {
+ return LogEvent.of(sequencer.getAndIncrement(), isLoggable, name,
+ className, methodName, level, bundle, supplier, thrown, params);
+ }
+
+ }
+
+ public static class LogProducerFinder extends LoggerFinder {
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+ final ConcurrentHashMap<String, LoggerImpl> system = new ConcurrentHashMap<>();
+ final ConcurrentHashMap<String, LoggerImpl> user = new ConcurrentHashMap<>();
+
+ public class LoggerImpl implements Logger, PlatformLogger.Bridge {
+ private final String name;
+ private sun.util.logging.PlatformLogger.Level level = sun.util.logging.PlatformLogger.Level.INFO;
+ private sun.util.logging.PlatformLogger.Level OFF = sun.util.logging.PlatformLogger.Level.OFF;
+ private sun.util.logging.PlatformLogger.Level FINE = sun.util.logging.PlatformLogger.Level.FINE;
+ private sun.util.logging.PlatformLogger.Level FINER = sun.util.logging.PlatformLogger.Level.FINER;
+ private sun.util.logging.PlatformLogger.Level FINEST = sun.util.logging.PlatformLogger.Level.FINEST;
+ private sun.util.logging.PlatformLogger.Level CONFIG = sun.util.logging.PlatformLogger.Level.CONFIG;
+ private sun.util.logging.PlatformLogger.Level INFO = sun.util.logging.PlatformLogger.Level.INFO;
+ private sun.util.logging.PlatformLogger.Level WARNING = sun.util.logging.PlatformLogger.Level.WARNING;
+ private sun.util.logging.PlatformLogger.Level SEVERE = sun.util.logging.PlatformLogger.Level.SEVERE;
+
+ public LoggerImpl(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean isLoggable(Level level) {
+ return this.level != OFF && this.level.intValue() <= level.getSeverity();
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle,
+ String key, Throwable thrown) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void log(Level level, ResourceBundle bundle,
+ String format, Object... params) {
+ throw new UnsupportedOperationException();
+ }
+
+ void log(LogEvent event) {
+ eventQueue.add(event);
+ }
+
+ @Override
+ public void log(Level level, Supplier<String> msgSupplier) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void log(Level level, Supplier<String> msgSupplier,
+ Throwable thrown) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void log(sun.util.logging.PlatformLogger.Level level, String msg) {
+ log(LogEvent.of(isLoggable(level), name, null, null,
+ level, null, msg, null, (Object[])null));
+ }
+
+ @Override
+ public void log(sun.util.logging.PlatformLogger.Level level,
+ Supplier<String> msgSupplier) {
+ log(LogEvent.of(isLoggable(level), name, null, null,
+ level, null, msgSupplier, null, (Object[])null));
+ }
+
+ @Override
+ public void log(sun.util.logging.PlatformLogger.Level level, String msg,
+ Object... params) {
+ log(LogEvent.of(isLoggable(level), name, null, null,
+ level, null, msg, null, params));
+ }
+
+ @Override
+ public void log(sun.util.logging.PlatformLogger.Level level, String msg,
+ Throwable thrown) {
+ log(LogEvent.of(isLoggable(level), name, null, null,
+ level, null, msg, thrown, (Object[])null));
+ }
+
+ @Override
+ public void log(sun.util.logging.PlatformLogger.Level level, Throwable thrown,
+ Supplier<String> msgSupplier) {
+ log(LogEvent.of(isLoggable(level), name, null, null,
+ level, null, msgSupplier, thrown, (Object[])null));
+ }
+
+ @Override
+ public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, String msg) {
+ log(LogEvent.of(isLoggable(level), name,
+ sourceClass, sourceMethod,
+ level, null, msg, null, (Object[])null));
+ }
+
+ @Override
+ public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, Supplier<String> msgSupplier) {
+ log(LogEvent.of(isLoggable(level), name,
+ sourceClass, sourceMethod,
+ level, null, msgSupplier, null, (Object[])null));
+ }
+
+ @Override
+ public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, String msg, Object... params) {
+ log(LogEvent.of(isLoggable(level), name,
+ sourceClass, sourceMethod,
+ level, null, msg, null, params));
+ }
+
+ @Override
+ public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, String msg, Throwable thrown) {
+ log(LogEvent.of(isLoggable(level), name,
+ sourceClass, sourceMethod,
+ level, null, msg, thrown, (Object[])null));
+ }
+
+ @Override
+ public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, Throwable thrown,
+ Supplier<String> msgSupplier) {
+ log(LogEvent.of(isLoggable(level), name,
+ sourceClass, sourceMethod,
+ level, null, msgSupplier, thrown, (Object[])null));
+ }
+
+ @Override
+ public void logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, ResourceBundle bundle, String msg,
+ Object... params) {
+ log(LogEvent.of(isLoggable(level), name,
+ sourceClass, sourceMethod,
+ level, bundle, msg, null, params));
+ }
+
+ @Override
+ public void logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
+ String msg, Object... params) {
+ log(LogEvent.of(isLoggable(level), name, null, null,
+ level, bundle, msg, null, params));
+ }
+
+ @Override
+ public void logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, ResourceBundle bundle, String msg,
+ Throwable thrown) {
+ log(LogEvent.of(isLoggable(level), name,
+ sourceClass, sourceMethod,
+ level, bundle, msg, thrown, (Object[])null));
+ }
+
+ @Override
+ public void logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle,
+ String msg, Throwable thrown) {
+ log(LogEvent.of(isLoggable(level), name, null, null,
+ level, bundle, msg, thrown, (Object[])null));
+ }
+
+ @Override
+ public boolean isLoggable(sun.util.logging.PlatformLogger.Level level) {
+ return this.level != OFF && level.intValue()
+ >= this.level.intValue();
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return this.level != OFF;
+ }
+
+
+ }
+
+ @Override
+ public Logger getLogger(String name, Class<?> caller) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGERFINDER_PERMISSION);
+ }
+ PrivilegedAction<ClassLoader> pa = () -> caller.getClassLoader();
+ ClassLoader callerLoader = AccessController.doPrivileged(pa);
+ if (callerLoader == null) {
+ return system.computeIfAbsent(name, (n) -> new LoggerImpl(n));
+ } else {
+ return user.computeIfAbsent(name, (n) -> new LoggerImpl(n));
+ }
+ }
+ }
+
+ static final sun.util.logging.PlatformLogger.Level[] julLevels = {
+ sun.util.logging.PlatformLogger.Level.ALL,
+ sun.util.logging.PlatformLogger.Level.FINEST,
+ sun.util.logging.PlatformLogger.Level.FINER,
+ sun.util.logging.PlatformLogger.Level.FINE,
+ sun.util.logging.PlatformLogger.Level.CONFIG,
+ sun.util.logging.PlatformLogger.Level.INFO,
+ sun.util.logging.PlatformLogger.Level.WARNING,
+ sun.util.logging.PlatformLogger.Level.SEVERE,
+ sun.util.logging.PlatformLogger.Level.OFF,
+ };
+
+ public static class MyBundle extends ResourceBundle {
+
+ final ConcurrentHashMap map = new ConcurrentHashMap();
+
+ @Override
+ protected Object handleGetObject(String key) {
+ if (key.contains(" (translated)")) {
+ throw new RuntimeException("Unexpected key: " + key);
+ }
+ return map.computeIfAbsent(key, k -> k + " (translated)");
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ return Collections.enumeration(map.keySet());
+ }
+
+ }
+
+ public static class MyHandler extends Handler {
+
+ @Override
+ public java.util.logging.Level getLevel() {
+ return java.util.logging.Level.ALL;
+ }
+
+ @Override
+ public void publish(LogRecord record) {
+ eventQueue.add(LogEvent.of(sequencer.getAndIncrement(),
+ true, record.getLoggerName(),
+ record.getSourceClassName(),
+ record.getSourceMethodName(),
+ PlatformLogger.Level.valueOf(record.getLevel().getName()),
+ record.getResourceBundle(), record.getMessage(),
+ record.getThrown(), record.getParameters()));
+ }
+ @Override
+ public void flush() {
+ }
+ @Override
+ public void close() throws SecurityException {
+ }
+
+ }
+
+ public static class MyLoggerBundle extends MyBundle {
+
+ }
+
+ static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS};
+
+ static void setSecurityManager() {
+ if (System.getSecurityManager() == null) {
+ Policy.setPolicy(new SimplePolicy(allowControl, allowAccess, allowAll));
+ System.setSecurityManager(new SecurityManager());
+ }
+ }
+
+ public static void main(String[] args) {
+ if (args.length == 0)
+ args = new String[] {
+ //"NOSECURITY",
+ "NOPERMISSIONS",
+ "WITHPERMISSIONS"
+ };
+
+
+ Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> {
+ LoggerFinder provider;
+ switch (testCase) {
+ case NOSECURITY:
+ System.out.println("\n*** Without Security Manager\n");
+ provider = LoggerFinder.getLoggerFinder();
+ test(provider, true);
+ System.out.println("Tetscase count: " + sequencer.get());
+ break;
+ case NOPERMISSIONS:
+ System.out.println("\n*** With Security Manager, without permissions\n");
+ setSecurityManager();
+ try {
+ provider = LoggerFinder.getLoggerFinder();
+ throw new RuntimeException("Expected exception not raised");
+ } catch (AccessControlException x) {
+ if (!LOGGERFINDER_PERMISSION.equals(x.getPermission())) {
+ throw new RuntimeException("Unexpected permission check", x);
+ }
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = LoggerFinder.getLoggerFinder();
+ } finally {
+ allowControl.get().set(control);
+ }
+ }
+ test(provider, false);
+ System.out.println("Tetscase count: " + sequencer.get());
+ break;
+ case WITHPERMISSIONS:
+ System.out.println("\n*** With Security Manager, with access permission\n");
+ setSecurityManager();
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = LoggerFinder.getLoggerFinder();
+ } finally {
+ allowControl.get().set(control);
+ }
+ final boolean access = allowAccess.get().get();
+ try {
+ allowAccess.get().set(true);
+ test(provider, true);
+ } finally {
+ allowAccess.get().set(access);
+ }
+ break;
+ default:
+ throw new RuntimeException("Unknown test case: " + testCase);
+ }
+ });
+ System.out.println("\nPASSED: Tested " + sequencer.get() + " cases.");
+ }
+
+ public static void test(LoggerFinder provider, boolean hasRequiredPermissions) {
+
+ final Map<PlatformLogger, String> loggerDescMap = new HashMap<>();
+
+ PlatformLogger sysLogger1 = null;
+ try {
+ sysLogger1 = PlatformLogger.getLogger("foo");
+ loggerDescMap.put(sysLogger1, "PlatformLogger.getLogger(\"foo\")");
+ if (!hasRequiredPermissions) {
+ throw new RuntimeException("Managed to obtain a system logger without permission");
+ }
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(SimplePolicy.ACCESS_LOGGING)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ final boolean old = allowAccess.get().get();
+ allowAccess.get().set(true);
+ try {
+ sysLogger1 = PlatformLogger.getLogger("foo");
+ loggerDescMap.put(sysLogger1, "PlatformLogger.getLogger(\"foo\")");
+ } finally {
+ allowAccess.get().set(old);
+ }
+ System.out.println("Got expected exception for system logger: " + acx);
+ }
+
+ final LogProducerFinder.LoggerImpl sysSink;
+ boolean old = allowControl.get().get();
+ allowControl.get().set(true);
+ try {
+ sysSink = LogProducerFinder.LoggerImpl.class.cast(
+ provider.getLogger("foo", Thread.class));
+ } finally {
+ allowControl.get().set(old);
+ }
+
+ testLogger(provider, loggerDescMap, "foo", null, sysLogger1, sysSink);
+ }
+
+ public static class Foo {
+
+ }
+
+ static void verbose(String msg) {
+ if (VERBOSE) {
+ System.out.println(msg);
+ }
+ }
+
+ static void checkLogEvent(LoggerFinder provider, String desc,
+ LogEvent expected) {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+
+ static void checkLogEvent(LoggerFinder provider, String desc,
+ LogEvent expected, boolean expectNotNull) {
+ LogEvent actual = eventQueue.poll();
+ if (actual == null && !expectNotNull) return;
+ if (actual != null && !expectNotNull) {
+ throw new RuntimeException("Unexpected log event found for " + desc
+ + "\n\tgot: " + actual);
+ }
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+
+ static void setLevel( LogProducerFinder.LoggerImpl sink,
+ sun.util.logging.PlatformLogger.Level loggerLevel) {
+ sink.level = loggerLevel;
+ }
+
+ // Calls the methods defined on LogProducer and verify the
+ // parameters received by the underlying LogProducerFinder.LoggerImpl
+ // logger.
+ private static void testLogger(LoggerFinder provider,
+ Map<PlatformLogger, String> loggerDescMap,
+ String name,
+ ResourceBundle loggerBundle,
+ PlatformLogger logger,
+ LogProducerFinder.LoggerImpl sink) {
+
+ System.out.println("Testing " + loggerDescMap.get(logger) + " [" + logger +"]");
+ final sun.util.logging.PlatformLogger.Level OFF = sun.util.logging.PlatformLogger.Level.OFF;
+ final sun.util.logging.PlatformLogger.Level ALL = sun.util.logging.PlatformLogger.Level.OFF;
+
+ Foo foo = new Foo();
+ String fooMsg = foo.toString();
+ System.out.println("\tlogger.log(messageLevel, fooMsg)");
+ System.out.println("\tlogger.<level>(fooMsg)");
+ for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ if (messageLevel == ALL || messageLevel == OFF) continue;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, loggerBundle,
+ fooMsg, (Throwable)null, (Object[])null);
+ String desc2 = "logger." + messageLevel.toString().toLowerCase()
+ + "(fooMsg): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ if (messageLevel == sun.util.logging.PlatformLogger.Level.FINEST) {
+ logger.finest(fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == sun.util.logging.PlatformLogger.Level.FINER) {
+ logger.finer(fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == sun.util.logging.PlatformLogger.Level.FINE) {
+ logger.fine(fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == sun.util.logging.PlatformLogger.Level.CONFIG) {
+ logger.config(fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == sun.util.logging.PlatformLogger.Level.INFO) {
+ logger.info(fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == sun.util.logging.PlatformLogger.Level.WARNING) {
+ logger.warning(fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == sun.util.logging.PlatformLogger.Level.SEVERE) {
+ logger.severe(fooMsg);
+ checkLogEvent(provider, desc2, expected);
+ }
+ }
+ }
+
+ String format = "two params [{1} {2}]";
+ Object arg1 = foo;
+ Object arg2 = fooMsg;
+ System.out.println("\tlogger.log(messageLevel, format, arg1, arg2)");
+ for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ if (messageLevel == ALL || messageLevel == OFF) continue;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, loggerBundle,
+ format, (Throwable)null, arg1, arg2);
+ String desc2 = "logger." + messageLevel.toString().toLowerCase()
+ + "(format, foo, fooMsg): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ if (messageLevel == sun.util.logging.PlatformLogger.Level.FINEST) {
+ logger.finest(format, arg1, arg2);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == sun.util.logging.PlatformLogger.Level.FINER) {
+ logger.finer(format, arg1, arg2);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == sun.util.logging.PlatformLogger.Level.FINE) {
+ logger.fine(format, arg1, arg2);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == sun.util.logging.PlatformLogger.Level.CONFIG) {
+ logger.config(format, arg1, arg2);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == sun.util.logging.PlatformLogger.Level.INFO) {
+ logger.info(format, arg1, arg2);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == sun.util.logging.PlatformLogger.Level.WARNING) {
+ logger.warning(format, arg1, arg2);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == sun.util.logging.PlatformLogger.Level.SEVERE) {
+ logger.severe(format, arg1, arg2);
+ checkLogEvent(provider, desc2, expected);
+ }
+ }
+ }
+
+ Throwable thrown = new Exception("OK: log me!");
+ System.out.println("\tlogger.log(messageLevel, fooMsg, thrown)");
+ for (sun.util.logging.PlatformLogger.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (sun.util.logging.PlatformLogger.Level messageLevel :julLevels) {
+ if (messageLevel == ALL || messageLevel == OFF) continue;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, loggerBundle,
+ fooMsg, thrown, (Object[])null);
+ String desc2 = "logger." + messageLevel.toString().toLowerCase()
+ + "(fooMsg, thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ if (messageLevel == sun.util.logging.PlatformLogger.Level.FINEST) {
+ logger.finest(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == sun.util.logging.PlatformLogger.Level.FINER) {
+ logger.finer(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == sun.util.logging.PlatformLogger.Level.FINE) {
+ logger.fine(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == sun.util.logging.PlatformLogger.Level.CONFIG) {
+ logger.config(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == sun.util.logging.PlatformLogger.Level.INFO) {
+ logger.info(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == sun.util.logging.PlatformLogger.Level.WARNING) {
+ logger.warning(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected);
+ } else if (messageLevel == sun.util.logging.PlatformLogger.Level.SEVERE) {
+ logger.severe(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected);
+ }
+ }
+ }
+ }
+
+ final static class PermissionsBuilder {
+ final Permissions perms;
+ public PermissionsBuilder() {
+ this(new Permissions());
+ }
+ public PermissionsBuilder(Permissions perms) {
+ this.perms = perms;
+ }
+ public PermissionsBuilder add(Permission p) {
+ perms.add(p);
+ return this;
+ }
+ public PermissionsBuilder addAll(PermissionCollection col) {
+ if (col != null) {
+ for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
+ perms.add(e.nextElement());
+ }
+ }
+ return this;
+ }
+ public Permissions toPermissions() {
+ final PermissionsBuilder builder = new PermissionsBuilder();
+ builder.addAll(perms);
+ return builder.perms;
+ }
+ }
+
+ public static class SimplePolicy extends Policy {
+ final static RuntimePermission CONTROL = LOGGERFINDER_PERMISSION;
+ final static RuntimePermission ACCESS_LOGGER = new RuntimePermission("accessClassInPackage.jdk.internal.logger");
+ final static RuntimePermission ACCESS_LOGGING = new RuntimePermission("accessClassInPackage.sun.util.logging");
+
+ final Permissions permissions;
+ final Permissions allPermissions;
+ final ThreadLocal<AtomicBoolean> allowControl;
+ final ThreadLocal<AtomicBoolean> allowAccess;
+ final ThreadLocal<AtomicBoolean> allowAll;
+ public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl,
+ ThreadLocal<AtomicBoolean> allowAccess,
+ ThreadLocal<AtomicBoolean> allowAll) {
+ this.allowControl = allowControl;
+ this.allowAccess = allowAccess;
+ this.allowAll = allowAll;
+ permissions = new Permissions();
+ allPermissions = new PermissionsBuilder()
+ .add(new java.security.AllPermission())
+ .toPermissions();
+ }
+
+ Permissions getPermissions() {
+ if (allowControl.get().get() || allowAccess.get().get() || allowAll.get().get()) {
+ PermissionsBuilder builder = new PermissionsBuilder()
+ .addAll(permissions);
+ if (allowControl.get().get()) {
+ builder.add(CONTROL);
+ }
+ if (allowAccess.get().get()) {
+ builder.add(ACCESS_LOGGER);
+ builder.add(ACCESS_LOGGING);
+ }
+ if (allowAll.get().get()) {
+ builder.addAll(allPermissions);
+ }
+ return builder.toPermissions();
+ }
+ return permissions;
+ }
+
+ @Override
+ public boolean implies(ProtectionDomain domain, Permission permission) {
+ return getPermissions().implies(permission);
+ }
+
+ @Override
+ public PermissionCollection getPermissions(CodeSource codesource) {
+ return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
+ }
+
+ @Override
+ public PermissionCollection getPermissions(ProtectionDomain domain) {
+ return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/api/LoggerFinderAPITest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,497 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8140364
+ * @author danielfuchs
+ * @summary JDK implementation specific unit test for JDK internal artifacts.
+ * Tests the consistency of the LoggerFinder and JDK extensions.
+ * @modules java.base/sun.util.logging
+ * java.base/jdk.internal.logger
+ * @run main LoggerFinderAPITest
+ */
+
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.function.Supplier;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Handler;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import sun.util.logging.PlatformLogger;
+
+public class LoggerFinderAPITest {
+
+ static final Class<java.lang.System.Logger> spiLoggerClass
+ = java.lang.System.Logger.class;
+ static final Class<java.lang.System.Logger> jdkLoggerClass
+ = java.lang.System.Logger.class;
+ static final Class<sun.util.logging.PlatformLogger.Bridge> bridgeLoggerClass
+ = sun.util.logging.PlatformLogger.Bridge.class;
+ static final Class<java.util.logging.Logger> julLoggerClass
+ = java.util.logging.Logger.class;
+ static final Class<sun.util.logging.PlatformLogger.Bridge> julLogProducerClass
+ = PlatformLogger.Bridge.class;
+ static final Pattern julLogNames = Pattern.compile(
+ "^((log(p|rb)?)|severe|warning|info|config|fine|finer|finest|isLoggable)$");
+ static final Collection<Method> julLoggerIgnores;
+ static {
+ List<Method> ignores = new ArrayList<>();
+ try {
+ ignores.add(julLoggerClass.getDeclaredMethod("log", LogRecord.class));
+ } catch (NoSuchMethodException | SecurityException ex) {
+ throw new ExceptionInInitializerError(ex);
+ }
+ julLoggerIgnores = Collections.unmodifiableList(ignores);
+ }
+
+
+
+ // Don't require LoggerBridge to have a body for those methods
+ interface LoggerBridgeMethodsWithNoBody extends
+ PlatformLogger.Bridge, java.lang.System.Logger {
+
+ @Override
+ public default String getName() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public default boolean isLoggable(PlatformLogger.Level level) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public default void log(sun.util.logging.PlatformLogger.Level level,
+ String msg, Throwable thrown) {
+ }
+ @Override
+ public default void log(sun.util.logging.PlatformLogger.Level level,
+ Throwable thrown, Supplier<String> msgSupplier) {
+ }
+ @Override
+ public default void log(sun.util.logging.PlatformLogger.Level level,
+ Supplier<String> msgSupplier) {
+ }
+ @Override
+ public default void log(sun.util.logging.PlatformLogger.Level level, String msg) {
+ }
+ @Override
+ public default void log(sun.util.logging.PlatformLogger.Level level,
+ String format, Object... params) {
+ }
+ @Override
+ public default void logrb(sun.util.logging.PlatformLogger.Level level,
+ ResourceBundle bundle, String key, Throwable thrown) {
+ }
+ @Override
+ public default void logrb(sun.util.logging.PlatformLogger.Level level,
+ ResourceBundle bundle, String format, Object... params) {
+ }
+
+ @Override
+ public default void logrb(PlatformLogger.Level level,
+ String sourceClass, String sourceMethod,
+ ResourceBundle bundle, String msg, Throwable thrown) {
+ }
+
+ @Override
+ public default void logrb(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, ResourceBundle bundle, String msg,
+ Object... params) {
+ }
+
+ @Override
+ public default void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, Supplier<String> msgSupplier) {
+ }
+
+ @Override
+ public default void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, String msg, Object... params) {
+ }
+
+ @Override
+ public default void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, String msg, Throwable thrown) {
+ }
+
+ @Override
+ public default void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, String msg) {
+ }
+
+ @Override
+ public default void logp(PlatformLogger.Level level, String sourceClass,
+ String sourceMethod, Throwable thrown,
+ Supplier<String> msgSupplier) {
+ }
+
+ static boolean requiresDefaultBodyFor(Method m) {
+ try {
+ Method m2 = LoggerBridgeMethodsWithNoBody.class
+ .getDeclaredMethod(m.getName(),
+ m.getParameterTypes());
+ return !m2.isDefault();
+ } catch (NoSuchMethodException x) {
+ return true;
+ }
+ }
+ }
+
+ final boolean warnDuplicateMappings;
+ public LoggerFinderAPITest(boolean verbose) {
+ this.warnDuplicateMappings = verbose;
+ for (Handler h : Logger.getLogger("").getHandlers()) {
+ if (h instanceof ConsoleHandler) {
+ Logger.getLogger("").removeHandler(h);
+ }
+ }
+ Logger.getLogger("").addHandler( new Handler() {
+ @Override
+ public void publish(LogRecord record) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("GOT LogRecord: ")
+ .append(record.getLevel().getLocalizedName())
+ .append(": [").append(record.getLoggerName())
+ .append("] ").append(record.getSourceClassName())
+ .append('.')
+ .append(record.getSourceMethodName()).append(" -> ")
+ .append(record.getMessage())
+ .append(' ')
+ .append(record.getParameters() == null ? ""
+ : Arrays.toString(record.getParameters()))
+ ;
+ System.out.println(builder);
+ if (record.getThrown() != null) {
+ record.getThrown().printStackTrace(System.out);
+ }
+ }
+ @Override public void flush() {}
+ @Override public void close() {}
+ });
+ }
+
+ public Stream<Method> getJulLogMethodStream(Class<?> loggerClass) {
+
+ return Stream.of(loggerClass.getMethods()).filter((x) -> {
+ final Matcher m = julLogNames.matcher(x.getName());
+ return m.matches() ? x.getAnnotation(Deprecated.class) == null : false;
+ });
+ }
+
+ /**
+ * Tells whether a method invocation of 'origin' can be transformed in a
+ * method invocation of 'target'.
+ * This method only look at the parameter signatures, it doesn't look at
+ * the name, nor does it look at the return types.
+ * <p>
+ * Example:
+ * <ul>
+ * <li>java.util.logging.Logger.log(Level, String, Object) can be invoked as<br>
+ java.util.logging.spi.Logger.log(Level, String, Object...) because the
+ last parameter in 'target' is a varargs.</li>
+ * <li>java.util.logging.Logger.log(Level, String) can also be invoked as<br>
+ java.util.logging.spi.Logger.log(Level, String, Object...) for the
+ same reason.</li>
+ * </ul>
+ * <p>
+ * The algorithm is tailored for our needs: when the last parameter in the
+ * target is a vararg, and when origin & target have the same number of
+ * parameters, then we consider that the types of the last parameter *must*
+ * match.
+ * <p>
+ * Similarly - we do not consider that o(X x, Y y, Y y) matches t(X x, Y... y)
+ * although strictly speaking, it should...
+ *
+ * @param origin The method in the original class
+ * @param target The correspondent candidate in the target class
+ * @return true if a method invocation of 'origin' can be transformed in a
+ * method invocation of 'target'.
+ */
+ public boolean canBeInvokedAs(Method origin, Method target,
+ Map<Class<?>,Class<?>> substitutes) {
+ final Class<?>[] xParams = target.getParameterTypes();
+ final Class<?>[] mParams = Stream.of(origin.getParameterTypes())
+ .map((x) -> substitutes.getOrDefault(x, x))
+ .collect(Collectors.toList()).toArray(new Class<?>[0]);
+ if (Arrays.deepEquals(xParams, mParams)) return true;
+ if (target.isVarArgs()) {
+ if (xParams.length == mParams.length) {
+ if (xParams[xParams.length-1].isArray()) {
+ return mParams[mParams.length -1].equals(
+ xParams[xParams.length -1].getComponentType());
+ }
+ } else if (xParams.length == mParams.length + 1) {
+ return Arrays.deepEquals(
+ Arrays.copyOfRange(xParams, 0, xParams.length-1), mParams);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Look whether {@code otherClass} has a public method similar to m
+ * @param m
+ * @param otherClass
+ * @return
+ */
+ public Stream<Method> findInvokable(Method m, Class<?> otherClass) {
+ final Map<Class<?>,Class<?>> substitues =
+ Collections.singletonMap(java.util.logging.Level.class,
+ sun.util.logging.PlatformLogger.Level.class);
+ return Stream.of(otherClass.getMethods())
+ .filter((x) -> m.getName().equals(x.getName()))
+ .filter((x) -> canBeInvokedAs(m, x, substitues));
+ }
+
+ /**
+ * Test that the concrete Logger implementation passed as parameter
+ * overrides all the methods defined by its interface.
+ * @param julLogger A concrete implementation of System.Logger
+ * whose backend is a JUL Logger.
+ */
+ StringBuilder testDefaultJULLogger(java.lang.System.Logger julLogger) {
+ final StringBuilder errors = new StringBuilder();
+ if (!bridgeLoggerClass.isInstance(julLogger)) {
+ final String errorMsg =
+ "Logger returned by LoggerFactory.getLogger(\"foo\") is not a "
+ + bridgeLoggerClass + "\n\t" + julLogger;
+ System.err.println(errorMsg);
+ errors.append(errorMsg).append('\n');
+ }
+ final Class<? extends java.lang.System.Logger> xClass = julLogger.getClass();
+ List<Method> notOverridden =
+ Stream.of(bridgeLoggerClass.getDeclaredMethods()).filter((m) -> {
+ try {
+ Method x = xClass.getDeclaredMethod(m.getName(), m.getParameterTypes());
+ return x == null;
+ } catch (NoSuchMethodException ex) {
+ return !Modifier.isStatic(m.getModifiers());
+ }
+ }).collect(Collectors.toList());
+ notOverridden.stream().filter((x) -> {
+ boolean shouldOverride = true;
+ try {
+ final Method m = xClass.getMethod(x.getName(), x.getParameterTypes());
+ Method m2 = null;
+ try {
+ m2 = jdkLoggerClass.getDeclaredMethod(x.getName(), x.getParameterTypes());
+ } catch (Exception e) {
+
+ }
+ shouldOverride = m.isDefault() || m2 == null;
+ } catch (Exception e) {
+ // should override.
+ }
+ return shouldOverride;
+ }).forEach(x -> {
+ final String errorMsg = xClass.getName() + " should override\n\t" + x.toString();
+ System.err.println(errorMsg);
+ errors.append(errorMsg).append('\n');
+ });
+ if (notOverridden.isEmpty()) {
+ System.out.println(xClass + " overrides all methods from " + bridgeLoggerClass);
+ }
+ return errors;
+ }
+
+ public static class ResourceBundeParam extends ResourceBundle {
+ Map<String, String> map = Collections.synchronizedMap(new LinkedHashMap<>());
+ @Override
+ protected Object handleGetObject(String key) {
+ map.putIfAbsent(key, "${"+key+"}");
+ return map.get(key);
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ return Collections.enumeration(new LinkedHashSet<>(map.keySet()));
+ }
+
+ }
+
+ final ResourceBundle bundleParam =
+ ResourceBundle.getBundle(ResourceBundeParam.class.getName());
+
+ public static class ResourceBundeLocalized extends ResourceBundle {
+ Map<String, String> map = Collections.synchronizedMap(new LinkedHashMap<>());
+ @Override
+ protected Object handleGetObject(String key) {
+ map.putIfAbsent(key, "Localized:${"+key+"}");
+ return map.get(key);
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ return Collections.enumeration(new LinkedHashSet<>(map.keySet()));
+ }
+
+ }
+
+ final static ResourceBundle bundleLocalized =
+ ResourceBundle.getBundle(ResourceBundeLocalized.class.getName());
+
+ final Map<Class<?>, Object> params = new HashMap<>();
+ {
+ params.put(String.class, "TestString");
+ params.put(sun.util.logging.PlatformLogger.Level.class, sun.util.logging.PlatformLogger.Level.WARNING);
+ params.put(java.lang.System.Logger.Level.class, java.lang.System.Logger.Level.WARNING);
+ params.put(ResourceBundle.class, bundleParam);
+ params.put(Throwable.class, new Throwable("TestThrowable (Please ignore it!)"));
+ params.put(Object[].class, new Object[] {"One", "Two"});
+ params.put(Object.class, new Object() {
+ @Override public String toString() { return "I am an object!"; }
+ });
+ }
+
+ public Object[] getParamsFor(Method m) {
+ final Object[] res = new Object[m.getParameterCount()];
+ final Class<?>[] sig = m.getParameterTypes();
+ if (res.length == 0) {
+ return res;
+ }
+ for (int i=0; i<res.length; i++) {
+ Object p = params.get(sig[i]);
+ if (p == null && sig[i].equals(Supplier.class)) {
+ final String msg = "SuppliedMsg["+i+"]";
+ p = (Supplier<String>) () -> msg;
+ }
+ if (p instanceof String) {
+ res[i] = String.valueOf(p)+"["+i+"]";
+ } else {
+ res[i] = p;
+ }
+ }
+ return res;
+ }
+
+ public void invokeOn(java.lang.System.Logger logger, Method m) {
+ Object[] p = getParamsFor(m);
+ try {
+ m.invoke(logger, p);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to invoke "+m.toString(), e);
+ }
+ }
+
+ public void testAllJdkExtensionMethods(java.lang.System.Logger logger) {
+ Stream.of(jdkLoggerClass.getDeclaredMethods())
+ .filter(m -> !Modifier.isStatic(m.getModifiers()))
+ .forEach((m) -> invokeOn(logger, m));
+ }
+
+ public void testAllAPIMethods(java.lang.System.Logger logger) {
+ Stream.of(spiLoggerClass.getDeclaredMethods())
+ .filter(m -> !Modifier.isStatic(m.getModifiers()))
+ .forEach((m) -> invokeOn(logger, m));
+ }
+
+ public void testAllBridgeMethods(java.lang.System.Logger logger) {
+ Stream.of(bridgeLoggerClass.getDeclaredMethods())
+ .filter(m -> !Modifier.isStatic(m.getModifiers()))
+ .forEach((m) -> invokeOn(logger, m));
+ }
+
+ public void testAllLogProducerMethods(java.lang.System.Logger logger) {
+ Stream.of(julLogProducerClass.getDeclaredMethods())
+ .filter(m -> !Modifier.isStatic(m.getModifiers()))
+ .forEach((m) -> invokeOn(logger, m));
+ }
+
+ public StringBuilder testGetLoggerOverriddenOnSpi() {
+ final StringBuilder errors = new StringBuilder();
+ Stream.of(jdkLoggerClass.getDeclaredMethods())
+ .filter(m -> Modifier.isStatic(m.getModifiers()))
+ .filter(m -> Modifier.isPublic(m.getModifiers()))
+ .filter(m -> !m.getName().equals("getLoggerFinder"))
+ .filter(m -> {
+ try {
+ final Method x = bridgeLoggerClass.getDeclaredMethod(m.getName(), m.getParameterTypes());
+ return x == null;
+ } catch (NoSuchMethodException ex) {
+ return true;
+ }
+ }).forEach(m -> {
+ final String errorMsg = bridgeLoggerClass.getName() + " should override\n\t" + m.toString();
+ System.err.println(errorMsg);
+ errors.append(errorMsg).append('\n');
+ });
+ if (errors.length() == 0) {
+ System.out.println(bridgeLoggerClass + " overrides all static methods from " + jdkLoggerClass);
+ } else {
+ if (errors.length() > 0) throw new RuntimeException(errors.toString());
+ }
+ return errors;
+ }
+
+ public static void main(String argv[]) throws Exception {
+ final LoggerFinderAPITest test = new LoggerFinderAPITest(false);
+ final StringBuilder errors = new StringBuilder();
+ errors.append(test.testGetLoggerOverriddenOnSpi());
+ java.lang.System.Logger julLogger =
+ java.lang.System.LoggerFinder.getLoggerFinder()
+ .getLogger("foo", LoggerFinderAPITest.class);
+ errors.append(test.testDefaultJULLogger(julLogger));
+ if (errors.length() > 0) throw new RuntimeException(errors.toString());
+ java.lang.System.Logger julSystemLogger =
+ java.lang.System.LoggerFinder.getLoggerFinder()
+ .getLogger("bar", Thread.class);
+ errors.append(test.testDefaultJULLogger(julSystemLogger));
+ if (errors.length() > 0) throw new RuntimeException(errors.toString());
+ java.lang.System.Logger julLocalizedLogger =
+ (java.lang.System.Logger)
+ System.getLogger("baz", bundleLocalized);
+ java.lang.System.Logger julLocalizedSystemLogger =
+ java.lang.System.LoggerFinder.getLoggerFinder()
+ .getLocalizedLogger("oof", bundleLocalized, Thread.class);
+ final String error = errors.toString();
+ if (!error.isEmpty()) throw new RuntimeException(error);
+ for (java.lang.System.Logger logger : new java.lang.System.Logger[] {
+ julLogger, julSystemLogger, julLocalizedLogger, julLocalizedSystemLogger
+ }) {
+ test.testAllJdkExtensionMethods(logger);
+ test.testAllAPIMethods(logger);
+ test.testAllBridgeMethods(logger);
+ test.testAllLogProducerMethods(logger);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,2316 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8140364
+ * @author danielfuchs
+ * @summary JDK implementation specific unit test for JDK internal artifacts.
+ * This test tests all the public API methods defined in the {@link
+ * java.lang.System.Logger} interface, as well as all the JDK
+ * internal methods defined in the
+ * {@link sun.util.logging.PlatformLogger.Bridge}
+ * interface, with loggers returned by {@link
+ * java.lang.System.LoggerFinder#getLogger(java.lang.String, java.lang.Class)}
+ * and {@link java.lang.System.LoggerFinder#getLocalizedLogger(java.lang.String,
+ * java.util.ResourceBundle, java.lang.Class)}
+ * (using both a null resource bundle and a non null resource bundle).
+ * It calls both the {@link java.lang.System} factory methods and
+ * {@link jdk.internal.logger.LazyLoggers} to obtains those loggers,
+ * and configure them with all possible known levels.
+ * @modules java.base/sun.util.logging
+ * java.base/jdk.internal.logger
+ * java.logging/sun.util.logging.internal
+ * @build LoggerFinderBackendTest SystemClassLoader
+ * @run main/othervm -Djava.system.class.loader=SystemClassLoader -Dtest.logger.hidesProvider=true LoggerFinderBackendTest
+ * @run main/othervm -Djava.system.class.loader=SystemClassLoader -Dtest.logger.hidesProvider=false LoggerFinderBackendTest
+ */
+
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.ResourceBundle;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.BiFunction;
+import java.util.function.BooleanSupplier;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.lang.System.LoggerFinder;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Handler;
+import sun.util.logging.PlatformLogger.Level;
+import java.util.logging.LogManager;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+import sun.util.logging.internal.LoggingProviderImpl;
+
+/**
+ * @author danielfuchs
+ */
+public class LoggerFinderBackendTest {
+
+ // whether the implementation of Logger try to do a best
+ // effort for logp... If the provider is not hidden, then
+ // the logp() implementation comes from LoggerWrapper - which does a
+ // best effort. Otherwise, it comes from the default provider
+ // which does support logp.
+ static final boolean BEST_EFFORT_FOR_LOGP =
+ !Boolean.getBoolean("test.logger.hidesProvider");
+ static final boolean VERBOSE = false;
+
+ static final Class<java.lang.System.Logger> spiLoggerClass =
+ java.lang.System.Logger.class;
+ static final Class<java.lang.System.Logger> jdkLoggerClass =
+ java.lang.System.Logger.class;
+ static final Class<sun.util.logging.PlatformLogger.Bridge> bridgeLoggerClass =
+ sun.util.logging.PlatformLogger.Bridge.class;
+
+ /** Use to retrieve the log records that were produced by the JUL backend */
+ static class LoggerTesterHandler extends Handler {
+ public final List<LogRecord> records =
+ Collections.synchronizedList(new ArrayList<>());
+
+ @Override
+ public void publish(LogRecord record) {
+ record.getSourceClassName(); record.getSourceMethodName();
+ records.add(record);
+ }
+
+ @Override
+ public void flush() {
+ }
+
+ @Override
+ public void close() throws SecurityException {
+ records.clear();
+ }
+
+ public void reset() {
+ records.clear();
+ }
+ }
+
+ /** The {@link LoggerTesterHandler} handler is added to the root logger. */
+ static final LoggerTesterHandler handler = new LoggerTesterHandler();
+ static {
+ for (Handler h : Logger.getLogger("").getHandlers()) {
+ if (h instanceof ConsoleHandler) {
+ Logger.getLogger("").removeHandler(h);
+ }
+ }
+ Logger.getLogger("").addHandler(handler);
+ }
+
+ /**
+ * A resource handler parameter that will be used when calling out the
+ * logrb-like methods - as well as when calling the level-specific
+ * methods that take a ResourceBundle parameter.
+ */
+ public static class ResourceBundeParam extends ResourceBundle {
+ Map<String, String> map = Collections.synchronizedMap(new LinkedHashMap<>());
+ @Override
+ protected Object handleGetObject(String key) {
+ map.putIfAbsent(key, "${"+key+"}");
+ return map.get(key);
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ return Collections.enumeration(new LinkedHashSet<>(map.keySet()));
+ }
+
+ }
+
+ final static ResourceBundle bundleParam =
+ ResourceBundle.getBundle(ResourceBundeParam.class.getName());
+
+ /**
+ * A resource handler parameter that will be used when creating localized
+ * loggers by calling {@link
+ * LoggerFinder#getLocalizedLogger(java.lang.String, java.util.ResourceBundle, java.lang.Class)}.
+ */
+ public static class ResourceBundeLocalized extends ResourceBundle {
+ Map<String, String> map = Collections.synchronizedMap(new LinkedHashMap<>());
+ @Override
+ protected Object handleGetObject(String key) {
+ map.putIfAbsent(key, "Localized:${"+key+"}");
+ return map.get(key);
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ return Collections.enumeration(new LinkedHashSet<>(map.keySet()));
+ }
+
+ }
+
+ /**
+ * The Levels enum is used to call all the level-specific methods on
+ * a logger instance. To minimize the amount of code it uses reflection
+ * to do so.
+ */
+ static Lookup lookup = MethodHandles.lookup();
+ public enum Levels {
+ /** Used to call all forms of Logger.log?(SEVERE, ...) */
+ SEVERE("severe", bridgeLoggerClass, Level.SEVERE, null, "error", false),
+ /** Used to call all forms of Logger.log?(WARNING,...) */
+ WARNING("warning", bridgeLoggerClass, Level.WARNING, "warning", "warning", false),
+ /** Used to call all forms of Logger.log?(INFO,...) */
+ INFO("info", bridgeLoggerClass, Level.INFO, "info", "info", false),
+ /** Used to call all forms of Logger.log?(CONFIG,...) */
+ CONFIG("config", bridgeLoggerClass, Level.CONFIG, null, "debug", false),
+ /** Used to call all forms of Logger.log?(FINE,...) */
+ FINE("fine", bridgeLoggerClass, Level.FINE, null, "debug", false),
+ /** Used to call all forms of Logger.log?(FINER,...) */
+ FINER("finer", bridgeLoggerClass, Level.FINER, null, "trace", false),
+ /** Used to call all forms of Logger.log?(FINEST,...) */
+ FINEST("finest", bridgeLoggerClass, Level.FINEST, null, "trace", false),
+ ;
+ public final String method; // The name of the level-specific method to call
+ public final Class<?> definingClass; // which interface j.u.logger.Logger or j.u.logging.spi.Logger defines it
+ public final Level platformLevel; // The platform Level it will be mapped to in Jul when Jul is the backend
+ public final String jdkExtensionToJUL; // The name of the method called on the JUL logger when JUL is the backend
+ public final String julToJdkExtension; // The name of the method called in the jdk extension by the default impl in jdk.internal.logging.Logger
+ public final String enableMethod; // The name of the isXxxxEnabled method
+ public final boolean hasSpecificIsEnabled;
+ Levels(String method, Class<?> definingClass, Level defaultMapping,
+ String jdkExtensionToJUL, String julToJdkExtension,
+ boolean hasSpecificIsEnabled) {
+ this.method = method;
+ this.definingClass = definingClass;
+ this.platformLevel = defaultMapping;
+ this.jdkExtensionToJUL = jdkExtensionToJUL;
+ this.julToJdkExtension = julToJdkExtension;
+ this.hasSpecificIsEnabled = hasSpecificIsEnabled;
+ if (hasSpecificIsEnabled) {
+ this.enableMethod = "is" + method.substring(0,1).toUpperCase()
+ + method.substring(1) + "Enabled";
+ } else {
+ this.enableMethod = "isLoggable";
+ }
+ }
+
+ /*
+ * calls this level specific method - e.g. if this==INFO: logger.info(msg);
+ */
+ public void level(Object logger, String msg) {
+ MethodType mt = MethodType.methodType(void.class, Level.class, String.class);
+ invoke("log", logger, mt, platformLevel, msg);
+ }
+
+ /*
+ * calls this level specific method - e.g. if this==INFO: logger.info(msgSupplier);
+ */
+ public void level(Object logger, Supplier<String> msgSupplier) {
+ MethodType mt = MethodType.methodType(void.class, Level.class, Supplier.class);
+ invoke("log", logger, mt, platformLevel, msgSupplier);
+ }
+
+ /*
+ * calls this level specific method - e.g. if this==INFO: logger.info(msg, params);
+ */
+ public void level(Object logger, String msg, Object... params) {
+ MethodType mt = MethodType.methodType(void.class, Level.class, String.class,
+ Object[].class);
+ invoke("log", logger, mt, platformLevel, msg, params);
+ }
+
+ /*
+ * calls this level specific method - e.g. if this==INFO: logger.info(msg, thrown);
+ */
+ public void level(Object logger, String msg, Throwable thrown) {
+ MethodType mt = MethodType.methodType(void.class, Level.class, String.class,
+ Throwable.class);
+ invoke("log", logger, mt, platformLevel, msg, thrown);
+ }
+
+ /*
+ * calls this level specific method - e.g. if this==INFO: logger.info(msgSupplier, thrown);
+ */
+ public void level(Object logger, Supplier<String> msgSupplier, Throwable thrown) {
+ MethodType mt = MethodType.methodType(void.class, Level.class,
+ Throwable.class, Supplier.class);
+ invoke("log", logger, mt, platformLevel, thrown, msgSupplier);
+ }
+
+ /*
+ * calls this level specific method - e.g. if this==INFO: logger.info(bundle, msg);
+ */
+ public void level(Object logger, String msg, ResourceBundle bundle) {
+ MethodType mt = MethodType.methodType(void.class, Level.class,
+ ResourceBundle.class, String.class, Object[].class);
+ invoke("logrb", logger, mt, platformLevel, bundle, msg, null);
+ }
+
+ public void level(Object logger, String msg, ResourceBundle bundle,
+ Object... params) {
+ MethodType mt = MethodType.methodType(void.class, Level.class,
+ ResourceBundle.class, String.class, Object[].class);
+ invoke("logrb", logger, mt, platformLevel, bundle, msg, params);
+ }
+
+ public void level(Object logger, String msg, ResourceBundle bundle,
+ Throwable thrown) {
+ MethodType mt = MethodType.methodType(void.class, Level.class,
+ ResourceBundle.class, String.class, Throwable.class);
+ invoke("logrb", logger, mt, platformLevel, bundle, msg, thrown);
+ }
+
+ public boolean isEnabled(Object logger) {
+ try {
+ if (hasSpecificIsEnabled) {
+ MethodType mt = MethodType.methodType(boolean.class);
+ final MethodHandle handle = lookup.findVirtual(definingClass,
+ enableMethod, mt).bindTo(logger);
+ return Boolean.class.cast(handle.invoke());
+ } else {
+ MethodType mt = MethodType.methodType(boolean.class,
+ Level.class);
+ final MethodHandle handle = lookup.findVirtual(definingClass,
+ enableMethod, mt).bindTo(logger);
+ return Boolean.class.cast(handle.invoke(platformLevel));
+ }
+ } catch (Throwable ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ private void invoke(String method, Object logger, MethodType mt, Object... args) {
+ try {
+ final int last = mt.parameterCount()-1;
+ boolean isVarargs = mt.parameterType(last).isArray();
+ final MethodHandle handle = lookup.findVirtual(definingClass,
+ method, mt).bindTo(logger);
+
+ final StringBuilder builder = new StringBuilder();
+ builder.append(logger.getClass().getSimpleName()).append('.')
+ .append(method).append('(');
+ String sep = "";
+ int offset = 0;
+ Object[] params = args;
+ for (int i=0; (i-offset) < params.length; i++) {
+ if (isVarargs && i == last) {
+ offset = last;
+ params = (Object[])args[i];
+ if (params == null) break;
+ }
+ Object p = params[i - offset];
+ String quote = (p instanceof String) ? "\"" : "";
+ builder.append(sep).append(quote).append(p).append(quote);
+ sep = ", ";
+ }
+ builder.append(')');
+ if (verbose) {
+ System.out.println(builder);
+ }
+ handle.invokeWithArguments(args);
+ } catch (Throwable ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ };
+
+ static interface Checker<LogResult, L> extends BiFunction<LogResult, L, Void> {}
+ static interface JdkLogTester
+ extends BiFunction<sun.util.logging.PlatformLogger.Bridge, Level, Void> {}
+ static interface SpiLogTester
+ extends BiFunction<java.lang.System.Logger, java.lang.System.Logger.Level, Void> {}
+
+ static interface MethodInvoker<LOGGER, LEVEL> {
+ public void logX(LOGGER logger, LEVEL level, Object... args);
+ }
+
+ public enum JdkLogMethodInvoker
+ implements MethodInvoker<sun.util.logging.PlatformLogger.Bridge, Level> {
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#log(Level, String, Object...)};
+ **/
+ LOG_STRING_PARAMS("log", MethodType.methodType(void.class,
+ Level.class, String.class, Object[].class)),
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#log(Level, String, Throwable)};
+ **/
+ LOG_STRING_THROWN("log", MethodType.methodType(void.class,
+ Level.class, String.class, Throwable.class)),
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#log(Level, Supplier<String>)};
+ **/
+ LOG_SUPPLIER("log", MethodType.methodType(void.class,
+ Level.class, Supplier.class)),
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#log(Level, Throwable, Supplier<String>)};
+ **/
+ LOG_SUPPLIER_THROWN("log", MethodType.methodType(void.class,
+ Level.class, Throwable.class, Supplier.class)),
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#logp(Level, String, String, String)};
+ **/
+ LOGP_STRING("logp", MethodType.methodType(void.class,
+ Level.class, String.class, String.class, String.class)),
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#logp(Level, String, String, String, Object...)};
+ **/
+ LOGP_STRING_PARAMS("logp", MethodType.methodType(void.class,
+ Level.class, String.class, String.class, String.class, Object[].class)),
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#logp(Level, String, String, String, Throwable)};
+ **/
+ LOGP_STRING_THROWN("logp", MethodType.methodType(void.class,
+ Level.class, String.class, String.class, String.class, Throwable.class)),
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#logp(Level, String, String, Supplier<String>)};
+ **/
+ LOGP_SUPPLIER("logp", MethodType.methodType(void.class,
+ Level.class, String.class, String.class, Supplier.class)),
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#logp(Level, String, String, Throwable, Supplier<String>)};
+ **/
+ LOGP_SUPPLIER_THROWN("logp", MethodType.methodType(void.class,
+ Level.class, String.class, String.class,
+ Throwable.class, Supplier.class)),
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#logrb(Level, ResourceBundle, String, Object...)};
+ **/
+ LOGRB_STRING_PARAMS("logrb", MethodType.methodType(void.class,
+ Level.class, ResourceBundle.class, String.class, Object[].class)),
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#logrb(Level, ResourceBundle, String, Throwable)};
+ **/
+ LOGRB_STRING_THROWN("logrb", MethodType.methodType(void.class,
+ Level.class, ResourceBundle.class, String.class, Throwable.class)),
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#logrb(Level, String, String, ResourceBundle, String, Object...)};
+ **/
+ LOGRBP_STRING_PARAMS("logrb", MethodType.methodType(void.class,
+ Level.class, String.class, String.class, ResourceBundle.class,
+ String.class, Object[].class)),
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#logrb(Level, String, String, ResourceBundle, String, Throwable)};
+ **/
+ LOGRBP_STRING_THROWN("logrb", MethodType.methodType(void.class,
+ Level.class, String.class, String.class, ResourceBundle.class,
+ String.class, Throwable.class)),
+ ;
+ final MethodType mt;
+ final String method;
+ JdkLogMethodInvoker(String method, MethodType mt) {
+ this.mt = mt;
+ this.method = method;
+ }
+ Object[] makeArgs(Level level, Object... rest) {
+ List<Object> list = new ArrayList<>(rest == null ? 1 : rest.length + 1);
+ list.add(level);
+ if (rest != null) {
+ list.addAll(Arrays.asList(rest));
+ }
+ return list.toArray(new Object[list.size()]);
+ }
+
+ @Override
+ public void logX(sun.util.logging.PlatformLogger.Bridge logger, Level level, Object... args) {
+ try {
+ MethodHandle handle = lookup.findVirtual(bridgeLoggerClass,
+ method, mt).bindTo(logger);
+ final int last = mt.parameterCount()-1;
+ boolean isVarargs = mt.parameterType(last).isArray();
+
+ args = makeArgs(level, args);
+
+ final StringBuilder builder = new StringBuilder();
+ builder.append(logger.getClass().getSimpleName()).append('.')
+ .append(this.method).append('(');
+ String sep = "";
+ int offset = 0;
+ Object[] params = args;
+ for (int i=0; (i-offset) < params.length; i++) {
+ if (isVarargs && i == last) {
+ offset = last;
+ params = (Object[])args[i];
+ if (params == null) break;
+ }
+ Object p = params[i - offset];
+ String quote = (p instanceof String) ? "\"" : "";
+ p = p instanceof Level ? "Level."+p : p;
+ builder.append(sep).append(quote).append(p).append(quote);
+ sep = ", ";
+ }
+ builder.append(')');
+ if (verbose) System.out.println(builder);
+ handle.invokeWithArguments(args);
+ } catch (Throwable ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ }
+
+
+ public enum SpiLogMethodInvoker implements MethodInvoker<java.lang.System.Logger,
+ java.lang.System.Logger.Level> {
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#log(Level, String, Object...)};
+ **/
+ LOG_STRING_PARAMS("log", MethodType.methodType(void.class,
+ java.lang.System.Logger.Level.class, String.class, Object[].class)),
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#log(Level, String, Throwable)};
+ **/
+ LOG_STRING_THROWN("log", MethodType.methodType(void.class,
+ java.lang.System.Logger.Level.class, String.class, Throwable.class)),
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#log(Level, Supplier<String>)};
+ **/
+ LOG_SUPPLIER("log", MethodType.methodType(void.class,
+ java.lang.System.Logger.Level.class, Supplier.class)),
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#log(Level, Throwable, Supplier<String>)};
+ **/
+ LOG_SUPPLIER_THROWN("log", MethodType.methodType(void.class,
+ java.lang.System.Logger.Level.class, Supplier.class, Throwable.class)),
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#log(Level, Supplier<String>)};
+ **/
+ LOG_OBJECT("log", MethodType.methodType(void.class,
+ java.lang.System.Logger.Level.class, Object.class)),
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#logrb(Level, ResourceBundle, String, Object...)};
+ **/
+ LOGRB_STRING_PARAMS("log", MethodType.methodType(void.class,
+ java.lang.System.Logger.Level.class, ResourceBundle.class,
+ String.class, Object[].class)),
+ /**
+ * Tests {@link
+ * jdk.internal.logging.Logger#logrb(Level, ResourceBundle, String, Throwable)};
+ **/
+ LOGRB_STRING_THROWN("log", MethodType.methodType(void.class,
+ java.lang.System.Logger.Level.class, ResourceBundle.class,
+ String.class, Throwable.class)),
+ ;
+ final MethodType mt;
+ final String method;
+ SpiLogMethodInvoker(String method, MethodType mt) {
+ this.mt = mt;
+ this.method = method;
+ }
+ Object[] makeArgs(java.lang.System.Logger.Level level, Object... rest) {
+ List<Object> list = new ArrayList<>(rest == null ? 1 : rest.length + 1);
+ list.add(level);
+ if (rest != null) {
+ list.addAll(Arrays.asList(rest));
+ }
+ return list.toArray(new Object[list.size()]);
+ }
+
+ @Override
+ public void logX(java.lang.System.Logger logger,
+ java.lang.System.Logger.Level level, Object... args) {
+ try {
+ MethodHandle handle = lookup.findVirtual(spiLoggerClass,
+ method, mt).bindTo(logger);
+ final int last = mt.parameterCount()-1;
+ boolean isVarargs = mt.parameterType(last).isArray();
+
+ args = makeArgs(level, args);
+
+ final StringBuilder builder = new StringBuilder();
+ builder.append(logger.getClass().getSimpleName()).append('.')
+ .append(this.method).append('(');
+ String sep = "";
+ int offset = 0;
+ Object[] params = args;
+ for (int i=0; (i-offset) < params.length; i++) {
+ if (isVarargs && i == last) {
+ offset = last;
+ params = (Object[])args[i];
+ if (params == null) break;
+ }
+ Object p = params[i - offset];
+ String quote = (p instanceof String) ? "\"" : "";
+ p = p instanceof Level ? "Level."+p : p;
+ builder.append(sep).append(quote).append(p).append(quote);
+ sep = ", ";
+ }
+ builder.append(')');
+ if (verbose) System.out.println(builder);
+ handle.invokeWithArguments(args);
+ } catch (Throwable ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ }
+
+
+ public abstract static class BackendTester<BackendRecord> {
+ static final Level[] levelMap = {Level.ALL, Level.FINER, Level.FINE,
+ Level.INFO, Level.WARNING, Level.SEVERE, Level.OFF};
+
+ abstract class BackendAdaptor {
+ public abstract String getLoggerName(BackendRecord res);
+ public abstract Object getLevel(BackendRecord res);
+ public abstract String getMessage(BackendRecord res);
+ public abstract String getSourceClassName(BackendRecord res);
+ public abstract String getSourceMethodName(BackendRecord res);
+ public abstract Throwable getThrown(BackendRecord res);
+ public abstract ResourceBundle getResourceBundle(BackendRecord res);
+ public abstract void setLevel(java.lang.System.Logger logger,
+ Level level);
+ public abstract void setLevel(java.lang.System.Logger logger,
+ java.lang.System.Logger.Level level);
+ public abstract List<BackendRecord> getBackendRecords();
+ public abstract void resetBackendRecords();
+ public boolean shouldBeLoggable(Levels level, Level loggerLevel) {
+ final Level logLevel = level.platformLevel;
+ return shouldBeLoggable(logLevel, loggerLevel);
+ }
+ public boolean shouldBeLoggable(Level logLevel, Level loggerLevel) {
+ return loggerLevel.intValue() != Level.OFF.intValue()
+ && logLevel.intValue() >= loggerLevel.intValue();
+ }
+ public boolean shouldBeLoggable(java.lang.System.Logger.Level logLevel,
+ java.lang.System.Logger.Level loggerLevel) {
+ return loggerLevel != java.lang.System.Logger.Level.OFF
+ && logLevel.ordinal() >= loggerLevel.ordinal();
+ }
+ public boolean isLoggable(java.lang.System.Logger logger, Level l) {
+ return bridgeLoggerClass.cast(logger).isLoggable(l);
+ }
+ public String getCallerClassName(Levels level, String clazz) {
+ return clazz != null ? clazz : Levels.class.getName();
+ }
+ public String getCallerClassName(MethodInvoker<?,?> logMethod,
+ String clazz) {
+ return clazz != null ? clazz : logMethod.getClass().getName();
+ }
+ public String getCallerMethodName(Levels level, String method) {
+ return method != null ? method : "invoke";
+ }
+ public String getCallerMethodName(MethodInvoker<?,?> logMethod,
+ String method) {
+ return method != null ? method : "logX";
+ }
+ public Object getMappedLevel(Object level) {
+ return level;
+ }
+
+ public Level toJUL(java.lang.System.Logger.Level level) {
+ return levelMap[level.ordinal()];
+ }
+ }
+
+ public final boolean isSystem;
+ public final Class<? extends java.lang.System.Logger> restrictedTo;
+ public final ResourceBundle localized;
+ public BackendTester(boolean isSystem) {
+ this(isSystem,null,null);
+ }
+ public BackendTester(boolean isSystem, ResourceBundle localized) {
+ this(isSystem,null,localized);
+ }
+ public BackendTester(boolean isSystem,
+ Class<? extends java.lang.System.Logger> restrictedTo) {
+ this(isSystem, restrictedTo, null);
+ }
+ public BackendTester(boolean isSystem,
+ Class<? extends java.lang.System.Logger> restrictedTo,
+ ResourceBundle localized) {
+ this.isSystem = isSystem;
+ this.restrictedTo = restrictedTo;
+ this.localized = localized;
+ }
+
+ public java.lang.System.Logger convert(java.lang.System.Logger logger) {
+ return logger;
+ }
+
+ public static Level[] LEVELS = {
+ Level.OFF,
+ Level.SEVERE, Level.WARNING, Level.INFO, Level.CONFIG,
+ Level.FINE, Level.FINER, Level.FINEST,
+ Level.ALL
+ };
+
+ abstract BackendAdaptor adaptor();
+
+ protected void checkRecord(Levels test, BackendRecord res, String loggerName,
+ Level level, String msg, String className, String methodName,
+ Throwable thrown, ResourceBundle bundle, Object... params) {
+ checkRecord(test, res, loggerName, level, ()->msg, className,
+ methodName, thrown, bundle, params);
+
+ }
+ protected void checkRecord(Levels test, BackendRecord res, String loggerName,
+ Level level, Supplier<String> msg, String className, String methodName,
+ Throwable thrown, ResourceBundle bundle, Object... params) {
+ checkRecord(test.method, res, loggerName, level, msg,
+ className, methodName, thrown, bundle, params);
+ }
+ protected <L> void checkRecord(String logMethod, BackendRecord res, String loggerName,
+ L level, Supplier<String> msg, String className, String methodName,
+ Throwable thrown, ResourceBundle bundle, Object... params) {
+ final BackendAdaptor analyzer = adaptor();
+ if (! Objects.equals(analyzer.getLoggerName(res), loggerName)) {
+ throw new RuntimeException(logMethod+": expected logger name "
+ + loggerName + " got " + analyzer.getLoggerName(res));
+ }
+ if (!Objects.equals(analyzer.getLevel(res), analyzer.getMappedLevel(level))) {
+ throw new RuntimeException(logMethod+": expected level "
+ + analyzer.getMappedLevel(level) + " got " + analyzer.getLevel(res));
+ }
+ if (!Objects.equals(analyzer.getMessage(res), msg.get())) {
+ throw new RuntimeException(logMethod+": expected message \""
+ + msg.get() + "\" got \"" + analyzer.getMessage(res) +"\"");
+ }
+ if (!Objects.equals(analyzer.getSourceClassName(res), className)) {
+ throw new RuntimeException(logMethod
+ + ": expected class name \"" + className
+ + "\" got \"" + analyzer.getSourceClassName(res) +"\"");
+ }
+ if (!Objects.equals(analyzer.getSourceMethodName(res), methodName)) {
+ throw new RuntimeException(logMethod
+ + ": expected method name \"" + methodName
+ + "\" got \"" + analyzer.getSourceMethodName(res) +"\"");
+ }
+ final Throwable thrownRes = analyzer.getThrown(res);
+ if (!Objects.equals(thrownRes, thrown)) {
+ throw new RuntimeException(logMethod
+ + ": expected throwable \"" + thrown
+ + "\" got \"" + thrownRes + "\"");
+ }
+ if (!Objects.equals(analyzer.getResourceBundle(res), bundle)) {
+ throw new RuntimeException(logMethod
+ + ": expected bundle \"" + bundle
+ + "\" got \"" + analyzer.getResourceBundle(res) +"\"");
+ }
+ }
+
+ public void testLevel(Levels level, java.lang.System.Logger logger,
+ String msg) {
+ Runnable test = () -> level.level(logger, msg);
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord(level, res, logger.getName(), l, msg,
+ adaptor().getCallerClassName(level, Levels.class.getName()),
+ adaptor().getCallerMethodName(level, "invoke"),
+ null, localized);
+ return null;
+ };
+ test("msg", level, logger, test, check);
+ }
+
+ public void testLevel(Levels level, java.lang.System.Logger logger,
+ String msg, Object... params) {
+ Runnable test = () -> level.level(logger, msg, (Object[])params);
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord(level, res, logger.getName(), l, msg,
+ adaptor().getCallerClassName(level, Levels.class.getName()),
+ adaptor().getCallerMethodName(level, "invoke"),
+ null, localized, (Object[])params);
+ return null;
+ };
+ test("msg, params", level, logger, test, check);
+ }
+
+ public void testLevel(Levels level, java.lang.System.Logger logger,
+ String msg, Throwable thrown) {
+ Runnable test = () -> level.level(logger, msg, thrown);
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord(level, res, logger.getName(), l, msg,
+ adaptor().getCallerClassName(level, Levels.class.getName()),
+ adaptor().getCallerMethodName(level, "invoke"),
+ thrown, localized);
+ return null;
+ };
+ test("msg, thrown", level, logger, test, check);
+ }
+
+ public void testLevel(Levels level, java.lang.System.Logger logger,
+ Supplier<String> msg) {
+ Runnable test = () -> level.level(logger, msg);
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord(level, res, logger.getName(), l, msg,
+ adaptor().getCallerClassName(level, Levels.class.getName()),
+ adaptor().getCallerMethodName(level, "invoke"),
+ null, null);
+ return null;
+ };
+ test("msgSupplier", level, logger, test, check);
+ }
+
+ public void testLevel(Levels level, java.lang.System.Logger logger,
+ Supplier<String> msg, Throwable thrown) {
+ Runnable test = () -> level.level(logger, msg, thrown);
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord(level, res, logger.getName(), l, msg,
+ adaptor().getCallerClassName(level, Levels.class.getName()),
+ adaptor().getCallerMethodName(level, "invoke"),
+ thrown, null);
+ return null;
+ };
+ test("throw, msgSupplier", level, logger, test, check);
+ }
+
+ public void testLevel(Levels level, java.lang.System.Logger logger,
+ String msg, ResourceBundle bundle) {
+ Runnable test = () -> level.level(logger, msg, bundle);
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord(level, res, logger.getName(), l, msg,
+ adaptor().getCallerClassName(level, Levels.class.getName()),
+ adaptor().getCallerMethodName(level, "invoke"),
+ null, bundle);
+ return null;
+ };
+ test("bundle, msg", level, logger, test, check);
+ }
+
+ public void testLevel(Levels level, java.lang.System.Logger logger,
+ String msg, ResourceBundle bundle, Object... params) {
+ Runnable test = () -> level.level(logger, msg, bundle, (Object[])params);
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord(level, res, logger.getName(), l, msg,
+ adaptor().getCallerClassName(level, Levels.class.getName()),
+ adaptor().getCallerMethodName(level, "invoke"),
+ null, bundle, (Object[])params);
+ return null;
+ };
+ test("bundle, msg, params", level, logger, test, check);
+ }
+
+ public void testLevel(Levels level, java.lang.System.Logger logger,
+ String msg, ResourceBundle bundle, Throwable thrown) {
+ Runnable test = () -> level.level(logger, msg, bundle, thrown);
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord(level, res, logger.getName(), l, msg,
+ adaptor().getCallerClassName(level, Levels.class.getName()),
+ adaptor().getCallerMethodName(level, "invoke"),
+ thrown, bundle);
+ return null;
+ };
+ test("bundle, msg, throwable", level, logger, test, check);
+ }
+
+ // System.Logger
+ public void testSpiLog(java.lang.System.Logger logger, String msg) {
+ Checker<BackendRecord, java.lang.System.Logger.Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l, () -> msg,
+ adaptor().getCallerClassName(
+ SpiLogMethodInvoker.LOG_STRING_PARAMS,
+ SpiLogMethodInvoker.class.getName()),
+ adaptor().getCallerMethodName(
+ SpiLogMethodInvoker.LOG_STRING_PARAMS,
+ "logX"), null, localized);
+ return null;
+ };
+ SpiLogTester tester = (x, level) -> {
+ SpiLogMethodInvoker.LOG_STRING_PARAMS.logX(x, level, msg, (Object[])null);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) -> "log(Level." + l + ", \"" + msg + "\")";
+ testSpiLog(logger, tester, check, nameProducer);
+ }
+
+ public void testSpiLog(java.lang.System.Logger logger,
+ ResourceBundle bundle, String msg) {
+ Checker<BackendRecord, java.lang.System.Logger.Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l, () -> msg,
+ adaptor().getCallerClassName(
+ SpiLogMethodInvoker.LOGRB_STRING_PARAMS,
+ SpiLogMethodInvoker.class.getName()),
+ adaptor().getCallerMethodName(
+ SpiLogMethodInvoker.LOGRB_STRING_PARAMS,
+ "logX"), null, bundle);
+ return null;
+ };
+ SpiLogTester tester = (x, level) -> {
+ SpiLogMethodInvoker.LOGRB_STRING_PARAMS.logX(x, level, bundle, msg, (Object[])null);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) -> "log(Level." + l
+ + ", bundle, \"" + msg + "\")";
+ testSpiLog(logger, tester, check, nameProducer);
+ }
+
+ public void testSpiLog(java.lang.System.Logger logger, String msg, Object... params) {
+ Checker<BackendRecord, java.lang.System.Logger.Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l, () -> msg,
+ adaptor().getCallerClassName(
+ SpiLogMethodInvoker.LOG_STRING_PARAMS,
+ SpiLogMethodInvoker.class.getName()),
+ adaptor().getCallerMethodName(
+ SpiLogMethodInvoker.LOG_STRING_PARAMS,
+ "logX"), null, localized, params);
+ return null;
+ };
+ SpiLogTester tester = (x, level) -> {
+ SpiLogMethodInvoker.LOG_STRING_PARAMS.logX(x, level, msg, params);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) -> "log(Level." + l + ", \"" + msg + "\", params...)";
+ testSpiLog(logger, tester, check, nameProducer);
+ }
+
+ public void testSpiLog(java.lang.System.Logger logger,
+ ResourceBundle bundle, String msg, Object... params) {
+ Checker<BackendRecord, java.lang.System.Logger.Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l, () -> msg,
+ adaptor().getCallerClassName(
+ SpiLogMethodInvoker.LOGRB_STRING_PARAMS,
+ SpiLogMethodInvoker.class.getName()),
+ adaptor().getCallerMethodName(
+ SpiLogMethodInvoker.LOGRB_STRING_PARAMS,
+ "logX"), null, bundle, params);
+ return null;
+ };
+ SpiLogTester tester = (x, level) -> {
+ SpiLogMethodInvoker.LOGRB_STRING_PARAMS.logX(x, level, bundle, msg, params);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) -> "log(Level." + l
+ + ", bundle, \"" + msg + "\", params...)";
+ testSpiLog(logger, tester, check, nameProducer);
+ }
+
+ public void testSpiLog(java.lang.System.Logger logger, String msg, Throwable thrown) {
+ Checker<BackendRecord, java.lang.System.Logger.Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l, () -> msg,
+ adaptor().getCallerClassName(
+ SpiLogMethodInvoker.LOG_STRING_THROWN,
+ SpiLogMethodInvoker.class.getName()),
+ adaptor().getCallerMethodName(
+ SpiLogMethodInvoker.LOG_STRING_THROWN,
+ "logX"), thrown, localized);
+ return null;
+ };
+ SpiLogTester tester = (x, level) -> {
+ SpiLogMethodInvoker.LOG_STRING_THROWN.logX(x, level, msg, thrown);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) ->
+ "log(Level." + l + ", \"" + msg + "\", thrown)";
+ testSpiLog(logger, tester, check, nameProducer);
+ }
+
+ public void testSpiLog(java.lang.System.Logger logger,
+ ResourceBundle bundle, String msg, Throwable thrown) {
+ Checker<BackendRecord, java.lang.System.Logger.Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l, () -> msg,
+ adaptor().getCallerClassName(
+ SpiLogMethodInvoker.LOGRB_STRING_THROWN,
+ SpiLogMethodInvoker.class.getName()),
+ adaptor().getCallerMethodName(
+ SpiLogMethodInvoker.LOGRB_STRING_THROWN,
+ "logX"), thrown, bundle);
+ return null;
+ };
+ SpiLogTester tester = (x, level) -> {
+ SpiLogMethodInvoker.LOGRB_STRING_THROWN.logX(x, level, bundle, msg, thrown);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) ->
+ "log(Level." + l + ", bundle, \"" + msg + "\", thrown)";
+ testSpiLog(logger, tester, check, nameProducer);
+ }
+
+ public void testSpiLog(java.lang.System.Logger logger, Supplier<String> msg) {
+ Checker<BackendRecord, java.lang.System.Logger.Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l, msg,
+ adaptor().getCallerClassName(
+ SpiLogMethodInvoker.LOG_SUPPLIER,
+ SpiLogMethodInvoker.class.getName()),
+ adaptor().getCallerMethodName(
+ SpiLogMethodInvoker.LOG_SUPPLIER,
+ "logX"), null, null);
+ return null;
+ };
+ SpiLogTester tester = (x, level) -> {
+ SpiLogMethodInvoker.LOG_SUPPLIER.logX(x, level, msg);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) ->
+ "log(Level." + l + ", () -> \"" + msg.get() + "\")";
+ testSpiLog(logger, tester, check, nameProducer);
+ }
+
+ public void testSpiLog(java.lang.System.Logger logger, Object obj) {
+ Checker<BackendRecord, java.lang.System.Logger.Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l, () -> obj.toString(),
+ adaptor().getCallerClassName(
+ SpiLogMethodInvoker.LOG_OBJECT,
+ SpiLogMethodInvoker.class.getName()),
+ adaptor().getCallerMethodName(
+ SpiLogMethodInvoker.LOG_OBJECT,
+ "logX"), null, null);
+ return null;
+ };
+ SpiLogTester tester = (x, level) -> {
+ SpiLogMethodInvoker.LOG_OBJECT.logX(x, level, obj);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) ->
+ "log(Level." + l + ", new "+obj.getClass().getSimpleName()+"(\""
+ + obj.toString() + "\"))";
+ testSpiLog(logger, tester, check, nameProducer);
+ }
+
+ public void testSpiLog(java.lang.System.Logger logger, Throwable thrown, Supplier<String> msg) {
+ Checker<BackendRecord, java.lang.System.Logger.Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l, msg,
+ adaptor().getCallerClassName(
+ SpiLogMethodInvoker.LOG_SUPPLIER_THROWN,
+ SpiLogMethodInvoker.class.getName()),
+ adaptor().getCallerMethodName(
+ SpiLogMethodInvoker.LOG_SUPPLIER_THROWN,
+ "logX"), thrown, null);
+ return null;
+ };
+ SpiLogTester tester = (x, level) -> {
+ SpiLogMethodInvoker.LOG_SUPPLIER_THROWN.logX(x, level, msg, thrown);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) ->
+ "log(Level." + l + ", () -> \"" + msg.get() + "\", thrown)";
+ testSpiLog(logger, tester, check, nameProducer);
+ }
+
+
+ // JDK
+
+ public void testLog(java.lang.System.Logger logger, String msg) {
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l, () -> msg,
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOG_STRING_PARAMS,
+ JdkLogMethodInvoker.class.getName()),
+ adaptor().getCallerMethodName(
+ JdkLogMethodInvoker.LOG_STRING_PARAMS,
+ "logX"), null, localized);
+ return null;
+ };
+ JdkLogTester tester = (x, level) -> {
+ JdkLogMethodInvoker.LOG_STRING_PARAMS.logX(x, level, msg, (Object[])null);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) -> "log(Level." + l + ", \"" + msg + "\")";
+ testJdkLog(logger, tester, check, nameProducer);
+ }
+
+ public void testLogrb(java.lang.System.Logger logger,
+ ResourceBundle bundle, String msg) {
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l, () -> msg,
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGRB_STRING_PARAMS,
+ JdkLogMethodInvoker.class.getName()),
+ adaptor().getCallerMethodName(
+ JdkLogMethodInvoker.LOGRB_STRING_PARAMS,
+ "logX"), null, bundle);
+ return null;
+ };
+ JdkLogTester tester = (x, level) -> {
+ JdkLogMethodInvoker.LOGRB_STRING_PARAMS.logX(x, level, bundle, msg, (Object[])null);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) -> "logrb(Level." + l
+ + ", bundle, \"" + msg + "\")";
+ testJdkLog(logger, tester, check, nameProducer);
+ }
+
+ public void testLog(java.lang.System.Logger logger, String msg, Object... params) {
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l, () -> msg,
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOG_STRING_PARAMS,
+ JdkLogMethodInvoker.class.getName()),
+ adaptor().getCallerMethodName(
+ JdkLogMethodInvoker.LOG_STRING_PARAMS,
+ "logX"), null, localized, params);
+ return null;
+ };
+ JdkLogTester tester = (x, level) -> {
+ JdkLogMethodInvoker.LOG_STRING_PARAMS.logX(x, level, msg, params);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) -> "log(Level." + l + ", \"" + msg + "\", params...)";
+ testJdkLog(logger, tester, check, nameProducer);
+ }
+
+ public void testLogrb(java.lang.System.Logger logger,
+ ResourceBundle bundle, String msg, Object... params) {
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l, () -> msg,
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGRB_STRING_PARAMS,
+ JdkLogMethodInvoker.class.getName()),
+ adaptor().getCallerMethodName(
+ JdkLogMethodInvoker.LOGRB_STRING_PARAMS,
+ "logX"), null, bundle, params);
+ return null;
+ };
+ JdkLogTester tester = (x, level) -> {
+ JdkLogMethodInvoker.LOGRB_STRING_PARAMS.logX(x, level, bundle, msg, params);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) -> "log(Level." + l
+ + ", bundle, \"" + msg + "\", params...)";
+ testJdkLog(logger, tester, check, nameProducer);
+ }
+
+ public void testLog(java.lang.System.Logger logger, String msg, Throwable thrown) {
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l, () -> msg,
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOG_STRING_THROWN,
+ JdkLogMethodInvoker.class.getName()),
+ adaptor().getCallerMethodName(
+ JdkLogMethodInvoker.LOG_STRING_THROWN,
+ "logX"), thrown, localized);
+ return null;
+ };
+ JdkLogTester tester = (x, level) -> {
+ JdkLogMethodInvoker.LOG_STRING_THROWN.logX(x, level, msg, thrown);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) ->
+ "log(Level." + l + ", \"" + msg + "\", thrown)";
+ testJdkLog(logger, tester, check, nameProducer);
+ }
+
+ public void testLogrb(java.lang.System.Logger logger,
+ ResourceBundle bundle, String msg, Throwable thrown) {
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l, () -> msg,
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGRB_STRING_THROWN,
+ JdkLogMethodInvoker.class.getName()),
+ adaptor().getCallerMethodName(
+ JdkLogMethodInvoker.LOGRB_STRING_THROWN,
+ "logX"), thrown, bundle);
+ return null;
+ };
+ JdkLogTester tester = (x, level) -> {
+ JdkLogMethodInvoker.LOGRB_STRING_THROWN.logX(x, level, bundle, msg, thrown);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) ->
+ "log(Level." + l + ", bundle, \"" + msg + "\", thrown)";
+ testJdkLog(logger, tester, check, nameProducer);
+ }
+
+ public void testLog(java.lang.System.Logger logger, Supplier<String> msg) {
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l, msg,
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOG_SUPPLIER,
+ JdkLogMethodInvoker.class.getName()),
+ adaptor().getCallerMethodName(
+ JdkLogMethodInvoker.LOG_SUPPLIER,
+ "logX"), null, null);
+ return null;
+ };
+ JdkLogTester tester = (x, level) -> {
+ JdkLogMethodInvoker.LOG_SUPPLIER.logX(x, level, msg);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) ->
+ "log(Level." + l + ", () -> \"" + msg.get() + "\")";
+ testJdkLog(logger, tester, check, nameProducer);
+ }
+
+ public void testLog(java.lang.System.Logger logger, Throwable thrown, Supplier<String> msg) {
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l, msg,
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOG_SUPPLIER_THROWN,
+ JdkLogMethodInvoker.class.getName()),
+ adaptor().getCallerMethodName(
+ JdkLogMethodInvoker.LOG_SUPPLIER_THROWN,
+ "logX"), thrown, null);
+ return null;
+ };
+ JdkLogTester tester = (x, level) -> {
+ JdkLogMethodInvoker.LOG_SUPPLIER_THROWN.logX(x, level, thrown, msg);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) ->
+ "log(Level." + l + ", () -> \"" + msg.get() + "\", thrown)";
+ testJdkLog(logger, tester, check, nameProducer);
+ }
+
+ static Supplier<String> logpMessage(ResourceBundle bundle,
+ String className, String methodName, Supplier<String> msg) {
+ if (BEST_EFFORT_FOR_LOGP && bundle == null
+ && (className != null || methodName != null)) {
+ final String cName = className == null ? "" : className;
+ final String mName = methodName == null ? "" : methodName;
+ return () -> {
+ String m = msg.get();
+ return String.format("[%s %s] %s", cName, mName, m == null ? "" : m);
+ };
+ } else {
+ return msg;
+ }
+ }
+
+ public void testLogp(java.lang.System.Logger logger, String className,
+ String methodName, String msg) {
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord("logp", res, logger.getName(), l,
+ logpMessage(localized, className, methodName, () -> msg),
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGP_STRING, className),
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGP_STRING, methodName),
+ null, localized);
+ return null;
+ };
+ JdkLogTester tester = (x, level) -> {
+ JdkLogMethodInvoker.LOGP_STRING.logX(x, level,
+ className, methodName, msg);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) ->
+ "logp(Level." + l + ", class, method, \"" + msg + "\")";
+ testJdkLog(logger, tester, check, nameProducer);
+ }
+
+ public void testLogrb(java.lang.System.Logger logger, String className,
+ String methodName, ResourceBundle bundle, String msg) {
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord("logp", res, logger.getName(), l, () -> msg,
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGRBP_STRING_PARAMS, className),
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGRBP_STRING_PARAMS, methodName),
+ null, bundle);
+ return null;
+ };
+ JdkLogTester tester = (x, level) -> {
+ JdkLogMethodInvoker.LOGRBP_STRING_PARAMS.logX(x, level,
+ className, methodName, bundle, msg, (Object[])null);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) ->
+ "logp(Level." + l + ", class, method, bundle, \"" + msg + "\")";
+ testJdkLog(logger, tester, check, nameProducer);
+ }
+
+ public void testLogp(java.lang.System.Logger logger, String className,
+ String methodName, String msg, Object... params) {
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord("logp", res, logger.getName(), l,
+ logpMessage(localized, className, methodName, () -> msg),
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGP_STRING_PARAMS, className),
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGP_STRING_PARAMS, methodName),
+ null, localized, params);
+ return null;
+ };
+ JdkLogTester tester = (x, level) -> {
+ JdkLogMethodInvoker.LOGP_STRING_PARAMS.logX(x, level,
+ className, methodName, msg, params);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) ->
+ "log(Level." + l + ", class, method, \"" + msg + "\", params...)";
+ testJdkLog(logger, tester, check, nameProducer);
+ }
+
+ public void testLogrb(java.lang.System.Logger logger, String className,
+ String methodName, ResourceBundle bundle, String msg,
+ Object... params) {
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord("logp", res, logger.getName(), l, () -> msg,
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGRBP_STRING_PARAMS, className),
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGRBP_STRING_PARAMS, methodName),
+ null, bundle, params);
+ return null;
+ };
+ JdkLogTester tester = (x, level) -> {
+ JdkLogMethodInvoker.LOGRBP_STRING_PARAMS.logX(x, level,
+ className, methodName, bundle, msg, params);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) ->
+ "log(Level." + l + ", class, method, bundle, \""
+ + msg + "\", params...)";
+ testJdkLog(logger, tester, check, nameProducer);
+ }
+
+ public void testLogp(java.lang.System.Logger logger, String className,
+ String methodName, String msg, Throwable thrown) {
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l,
+ logpMessage(localized, className, methodName, () -> msg),
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGP_STRING_THROWN, className),
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGP_STRING_THROWN, methodName),
+ thrown, localized);
+ return null;
+ };
+ JdkLogTester tester = (x, level) -> {
+ JdkLogMethodInvoker.LOGP_STRING_THROWN.logX(x, level,
+ className, methodName, msg, thrown);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) ->
+ "log(Level." + l + ", class, method, \"" + msg + "\", thrown)";
+ testJdkLog(logger, tester, check, nameProducer);
+ }
+
+ public void testLogrb(java.lang.System.Logger logger, String className,
+ String methodName, ResourceBundle bundle,
+ String msg, Throwable thrown) {
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l, () -> msg,
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGRBP_STRING_THROWN, className),
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGRBP_STRING_THROWN, methodName),
+ thrown, bundle);
+ return null;
+ };
+ JdkLogTester tester = (x, level) -> {
+ JdkLogMethodInvoker.LOGRBP_STRING_THROWN.logX(x, level,
+ className, methodName, bundle, msg, thrown);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) ->
+ "log(Level." + l + ", class, method, bundle, \"" + msg + "\", thrown)";
+ testJdkLog(logger, tester, check, nameProducer);
+
+ }
+
+ public void testLogp(java.lang.System.Logger logger, String className,
+ String methodName, Supplier<String> msg) {
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l,
+ logpMessage(null, className, methodName, msg),
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGP_SUPPLIER, className),
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGP_SUPPLIER, methodName),
+ null, null);
+ return null;
+ };
+ JdkLogTester tester = (x, level) -> {
+ JdkLogMethodInvoker.LOGP_SUPPLIER.logX(x, level,
+ className, methodName, msg);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) ->
+ "log(Level." + l + ", class, method, () -> \"" + msg.get() + "\")";
+ testJdkLog(logger, tester, check, nameProducer);
+ }
+
+ public void testLogp(java.lang.System.Logger logger, String className,
+ String methodName, Throwable thrown, Supplier<String> msg) {
+ Checker<BackendRecord, Level> check = (res, l) -> {
+ checkRecord("log", res, logger.getName(), l,
+ logpMessage(null, className, methodName, msg),
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGP_SUPPLIER_THROWN, className),
+ adaptor().getCallerClassName(
+ JdkLogMethodInvoker.LOGP_SUPPLIER_THROWN, methodName),
+ thrown, null);
+ return null;
+ };
+ JdkLogTester tester = (x, level) -> {
+ JdkLogMethodInvoker.LOGP_SUPPLIER_THROWN.logX(x, level,
+ className, methodName, thrown, msg);
+ return null;
+ };
+ Function<String, String> nameProducer = (l) ->
+ "log(Level." + l + ", class, method, () -> \"" + msg.get() + "\", thrown)";
+ testJdkLog(logger, tester, check, nameProducer);
+ }
+
+ private void testJdkLog(java.lang.System.Logger logger,
+ JdkLogTester log, Checker<BackendRecord,Level> check,
+ Function<String, String> nameProducer) {
+ if (restrictedTo != null) {
+ if (!bridgeLoggerClass.isAssignableFrom(restrictedTo)) {
+ if (VERBOSE) {
+ System.out.println("Skipping method from "
+ + bridgeLoggerClass);
+ }
+ return;
+ }
+ }
+ System.out.println("Testing Logger." + nameProducer.apply("*")
+ + " on " + logger);
+ final BackendAdaptor adaptor = adaptor();
+ for (Level loggerLevel : LEVELS) {
+ adaptor.setLevel(logger, loggerLevel);
+ for (Level l : LEVELS) {
+ check(logger, () -> log.apply(bridgeLoggerClass.cast(logger), l),
+ check, () -> adaptor.isLoggable(logger, l),
+ () -> adaptor.shouldBeLoggable(l, loggerLevel),
+ l, loggerLevel, nameProducer.apply(l.toString()));
+ }
+ }
+ }
+
+ private void testSpiLog(java.lang.System.Logger logger,
+ SpiLogTester log, Checker<BackendRecord, java.lang.System.Logger.Level> check,
+ Function<String, String> nameProducer) {
+ System.out.println("Testing System.Logger." + nameProducer.apply("*")
+ + " on " + logger);
+ final BackendAdaptor adaptor = adaptor();
+ for (java.lang.System.Logger.Level loggerLevel : java.lang.System.Logger.Level.values()) {
+
+ adaptor.setLevel(logger, loggerLevel);
+ for (java.lang.System.Logger.Level l : java.lang.System.Logger.Level.values()) {
+ check(logger, () -> log.apply(logger, l),
+ check, () -> logger.isLoggable(l),
+ () -> adaptor.shouldBeLoggable(l, loggerLevel),
+ l, loggerLevel, nameProducer.apply(l.toString()));
+ }
+ }
+ }
+
+ private void test(String args, Levels level, java.lang.System.Logger logger,
+ Runnable test, Checker<BackendRecord, Level> check) {
+ if (restrictedTo != null) {
+ if (!level.definingClass.isAssignableFrom(restrictedTo)) {
+ if (VERBOSE) {
+ System.out.println("Skipping method from "
+ + level.definingClass);
+ }
+ return;
+ }
+ }
+ String method = args.contains("bundle") ? "logrb" : "log";
+ System.out.println("Testing Logger."
+ + method + "(Level." + level.platformLevel
+ + ", "+ args + ")" + " on " + logger);
+ final BackendAdaptor adaptor = adaptor();
+ for (Level loggerLevel : LEVELS) {
+ adaptor.setLevel(logger, loggerLevel);
+ check(logger, test, check,
+ () -> level.isEnabled(logger),
+ () -> adaptor.shouldBeLoggable(level, loggerLevel),
+ level.platformLevel, loggerLevel, level.method);
+ }
+ }
+
+ private <L> void check(java.lang.System.Logger logger,
+ Runnable test, Checker<BackendRecord,L> check,
+ BooleanSupplier checkLevelEnabled,
+ BooleanSupplier shouldBeLoggable,
+ L logLevel, L loggerLevel, String logMethod) {
+ final BackendAdaptor adaptor = adaptor();
+ adaptor.resetBackendRecords();
+ test.run();
+ final List<BackendRecord> records = adaptor.getBackendRecords();
+ if (shouldBeLoggable.getAsBoolean()) {
+ if (!checkLevelEnabled.getAsBoolean()) {
+ throw new RuntimeException("Logger is not enabled for "
+ + logMethod
+ + " although logger level is " + loggerLevel);
+ }
+ if (records.size() != 1) {
+ throw new RuntimeException(loggerLevel + " [" +
+ logLevel + "] : Unexpected record sizes: "
+ + records.toString());
+ }
+ BackendRecord res = records.get(0);
+ check.apply(res, logLevel);
+ } else {
+ if (checkLevelEnabled.getAsBoolean()) {
+ throw new RuntimeException("Logger is enabled for "
+ + logMethod
+ + " although logger level is " + loggerLevel);
+ }
+ if (!records.isEmpty()) {
+ throw new RuntimeException(loggerLevel + " [" +
+ logLevel + "] : Unexpected record sizes: "
+ + records.toString());
+ }
+ }
+ }
+ }
+
+ public static class JULBackendTester extends BackendTester<LogRecord>{
+
+ public JULBackendTester(boolean isSystem) {
+ this(isSystem,null,null);
+ }
+ public JULBackendTester(boolean isSystem, ResourceBundle localized) {
+ this(isSystem,null,localized);
+ }
+ public JULBackendTester(boolean isSystem,
+ Class<? extends java.lang.System.Logger> restrictedTo) {
+ this(isSystem, restrictedTo, null);
+ }
+ public JULBackendTester(boolean isSystem,
+ Class<? extends java.lang.System.Logger> restrictedTo,
+ ResourceBundle localized) {
+ super(isSystem, restrictedTo, localized);
+ }
+
+ Logger getBackendLogger(String name) {
+ if (isSystem) {
+ return LoggingProviderImpl.getLogManagerAccess().demandLoggerFor(
+ LogManager.getLogManager(), name, Thread.class);
+ } else {
+ return Logger.getLogger(name);
+ }
+ }
+
+ class JULBackendAdaptor extends BackendAdaptor {
+ @Override
+ public String getLoggerName(LogRecord res) {
+ return res.getLoggerName();
+ }
+ @Override
+ public Level getLevel(LogRecord res) {
+ return Level.valueOf(res.getLevel().getName());
+ }
+ @Override
+ public String getMessage(LogRecord res) {
+ return res.getMessage();
+ }
+ @Override
+ public String getSourceClassName(LogRecord res) {
+ return res.getSourceClassName();
+ }
+ @Override
+ public String getSourceMethodName(LogRecord res) {
+ return res.getSourceMethodName();
+ }
+ @Override
+ public Throwable getThrown(LogRecord res) {
+ return res.getThrown();
+ }
+ @Override
+ public ResourceBundle getResourceBundle(LogRecord res) {
+ return res.getResourceBundle();
+ }
+ @Override
+ public void setLevel(java.lang.System.Logger logger, Level level) {
+ Logger backend = getBackendLogger(logger.getName());
+ backend.setLevel(java.util.logging.Level.parse(level.name()));
+ }
+ @Override
+ public void setLevel(java.lang.System.Logger logger, java.lang.System.Logger.Level level) {
+ setLevel(logger, toJUL(level));
+ }
+ @Override
+ public List<LogRecord> getBackendRecords() {
+ return handler.records;
+ }
+ @Override
+ public void resetBackendRecords() {
+ handler.reset();
+ }
+ @Override
+ public Level getMappedLevel(Object level) {
+ if (level instanceof java.lang.System.Logger.Level) {
+ return toJUL((java.lang.System.Logger.Level)level);
+ }
+ return (Level)level;
+ }
+ }
+
+ final JULBackendAdaptor julAdaptor = new JULBackendAdaptor();
+
+ @Override
+ BackendAdaptor adaptor() {
+ return julAdaptor;
+ }
+
+ }
+
+ public abstract static class BackendTesterFactory {
+ public abstract BackendTester createBackendTester(boolean isSystem);
+ public abstract BackendTester createBackendTester(boolean isSystem,
+ Class<? extends java.lang.System.Logger> restrictedTo);
+ public abstract BackendTester createBackendTester(boolean isSystem,
+ Class<? extends java.lang.System.Logger> restrictedTo,
+ ResourceBundle bundle);
+ public abstract BackendTester createBackendTester(boolean isSystem,
+ ResourceBundle bundle);
+ }
+
+ public static class JULBackendTesterFactory extends BackendTesterFactory {
+
+ @Override
+ public BackendTester createBackendTester(boolean isSystem) {
+ return new JULBackendTester(isSystem);
+ }
+
+ @Override
+ public BackendTester createBackendTester(boolean isSystem,
+ Class<? extends java.lang.System.Logger> restrictedTo) {
+ return new JULBackendTester(isSystem, restrictedTo);
+ }
+
+ @Override
+ public BackendTester createBackendTester(boolean isSystem,
+ Class<? extends java.lang.System.Logger> restrictedTo,
+ ResourceBundle bundle) {
+ return new JULBackendTester(isSystem, restrictedTo, bundle);
+ }
+
+ @Override
+ public BackendTester createBackendTester(boolean isSystem,
+ ResourceBundle bundle) {
+ return new JULBackendTester(isSystem, bundle);
+ }
+ }
+
+ public static class CustomLoggerFinder extends LoggerFinder {
+
+ static enum CustomLevel { OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL };
+ static CustomLevel[] customLevelMap = { CustomLevel.ALL,
+ CustomLevel.TRACE, CustomLevel.DEBUG, CustomLevel.INFO,
+ CustomLevel.WARN, CustomLevel.ERROR, CustomLevel.OFF
+ };
+ static class CustomLogRecord {
+ public final CustomLevel logLevel;
+ public final java.lang.System.Logger logger;
+ public final String msg;
+ public final Object[] params;
+ public final Throwable thrown;
+ public final ResourceBundle bundle;
+
+ CustomLogRecord(java.lang.System.Logger producer,
+ CustomLevel level, String msg) {
+ this(producer, level, msg, (ResourceBundle)null, (Throwable)null, (Object[])null);
+ }
+
+ CustomLogRecord(java.lang.System.Logger producer,
+ CustomLevel level, String msg, ResourceBundle bundle,
+ Throwable thrown, Object... params) {
+ this.logger = producer;
+ this.logLevel = level;
+ this.msg = msg;
+ this.params = params;
+ this.thrown = thrown;
+ this.bundle = bundle;
+ }
+ }
+
+ static final List<CustomLogRecord> records =
+ Collections.synchronizedList(new ArrayList<>());
+
+ static class CustomLogger implements java.lang.System.Logger {
+
+ final String name;
+ volatile CustomLevel level;
+ CustomLogger(String name) {
+ this.name = name;
+ this.level = CustomLevel.INFO;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ public void setLevel(CustomLevel level) {
+ this.level = level;
+ }
+
+
+ @Override
+ public boolean isLoggable(java.lang.System.Logger.Level level) {
+
+ return this.level != CustomLevel.OFF && this.level.ordinal()
+ >= customLevelMap[level.ordinal()].ordinal();
+ }
+
+ @Override
+ public void log(java.lang.System.Logger.Level level, ResourceBundle bundle, String key, Throwable thrown) {
+ if (isLoggable(level)) {
+ records.add(new CustomLogRecord(this, customLevelMap[level.ordinal()],
+ key, bundle, thrown));
+ }
+ }
+
+ @Override
+ public void log(java.lang.System.Logger.Level level, ResourceBundle bundle, String format, Object... params) {
+ if (isLoggable(level)) {
+ records.add(new CustomLogRecord(this, customLevelMap[level.ordinal()],
+ format, bundle, null, params));
+ }
+ }
+
+ }
+
+ final Map<String, java.lang.System.Logger> applicationLoggers =
+ Collections.synchronizedMap(new HashMap<>());
+ final Map<String, java.lang.System.Logger> systemLoggers =
+ Collections.synchronizedMap(new HashMap<>());
+
+ @Override
+ public java.lang.System.Logger getLogger(String name, Class<?> caller) {
+ ClassLoader callerLoader = caller.getClassLoader();
+ if (callerLoader == null) {
+ systemLoggers.putIfAbsent(name, new CustomLogger(name));
+ return systemLoggers.get(name);
+ } else {
+ applicationLoggers.putIfAbsent(name, new CustomLogger(name));
+ return applicationLoggers.get(name);
+ }
+ }
+
+ CustomLevel fromJul(Level level) {
+ if (level.intValue() == Level.OFF.intValue()) {
+ return CustomLevel.OFF;
+ } else if (level.intValue() > Level.SEVERE.intValue()) {
+ return CustomLevel.ERROR;
+ } else if (level.intValue() > Level.WARNING.intValue()) {
+ return CustomLevel.ERROR;
+ } else if (level.intValue() > Level.INFO.intValue()) {
+ return CustomLevel.WARN;
+ } else if (level.intValue() > Level.CONFIG.intValue()) {
+ return CustomLevel.INFO;
+ } else if (level.intValue() > Level.FINER.intValue()) {
+ return CustomLevel.DEBUG;
+ } else if (level.intValue() > Level.FINEST.intValue()) {
+ return CustomLevel.TRACE;
+ } else if (level.intValue() == Level.ALL.intValue()) {
+ return CustomLevel.ALL;
+ } else {
+ return CustomLevel.TRACE;
+ }
+ }
+
+ Level toJul(CustomLevel level) {
+ switch(level) {
+ case OFF: return Level.OFF;
+ case FATAL: return Level.SEVERE;
+ case ERROR: return Level.SEVERE;
+ case WARN: return Level.WARNING;
+ case INFO: return Level.INFO;
+ case DEBUG: return Level.FINE;
+ case TRACE: return Level.FINER;
+ case ALL: return Level.ALL;
+ default: throw new InternalError("No such level: "+level);
+ }
+ }
+
+ }
+
+ public static class CustomBackendTester extends
+ BackendTester<CustomLoggerFinder.CustomLogRecord> {
+
+ public final CustomLoggerFinder provider;
+
+ public CustomBackendTester(boolean isSystem) {
+ this(isSystem, null, null);
+ }
+
+ public CustomBackendTester(boolean isSystem,
+ Class<? extends java.lang.System.Logger> restrictedTo) {
+ this(isSystem, restrictedTo, null);
+ }
+
+ public CustomBackendTester(boolean isSystem,
+ ResourceBundle localized) {
+ this(isSystem, null, localized);
+ }
+
+ public CustomBackendTester(boolean isSystem,
+ Class<? extends java.lang.System.Logger> restrictedTo,
+ ResourceBundle localized) {
+ super(isSystem, restrictedTo, localized);
+ provider = (CustomLoggerFinder)java.lang.System.LoggerFinder.getLoggerFinder();
+ }
+
+ @Override
+ public java.lang.System.Logger convert(java.lang.System.Logger logger) {
+ if (restrictedTo != null && restrictedTo.isInstance(logger)) {
+ return logger;
+ } else if (restrictedTo == jdkLoggerClass) {
+ return logger;
+ } else {
+ return java.lang.System.Logger.class.cast(
+ sun.util.logging.PlatformLogger.Bridge.convert(logger));
+ }
+ }
+
+ class CustomBackendAdaptor extends BackendAdaptor {
+
+ @Override
+ public String getLoggerName(CustomLoggerFinder.CustomLogRecord res) {
+ return res.logger.getName();
+ }
+
+ @Override
+ public CustomLoggerFinder.CustomLevel getLevel(CustomLoggerFinder.CustomLogRecord res) {
+ return res.logLevel;
+ }
+
+ @Override
+ public String getMessage(CustomLoggerFinder.CustomLogRecord res) {
+ return res.msg;
+ }
+
+ @Override // we don't support source class name in our custom provider implementation
+ public String getSourceClassName(CustomLoggerFinder.CustomLogRecord res) {
+ return null;
+ }
+
+ @Override // we don't support source method name in our custom provider implementation
+ public String getSourceMethodName(CustomLoggerFinder.CustomLogRecord res) {
+ return null;
+ }
+
+ @Override
+ public Throwable getThrown(CustomLoggerFinder.CustomLogRecord res) {
+ return res.thrown;
+ }
+
+ @Override
+ public ResourceBundle getResourceBundle(CustomLoggerFinder.CustomLogRecord res) {
+ return res.bundle;
+ }
+
+ @Override
+ public void setLevel(java.lang.System.Logger logger, Level level) {
+ final CustomLoggerFinder.CustomLogger l =
+ (CustomLoggerFinder.CustomLogger)
+ (isSystem ? provider.getLogger(logger.getName(), Thread.class) :
+ provider.getLogger(logger.getName(), LoggerFinderBackendTest.class));
+ l.setLevel(provider.fromJul(level));
+ }
+ @Override
+ public void setLevel(java.lang.System.Logger logger,
+ java.lang.System.Logger.Level level) {
+ setLevel(logger, toJUL(level));
+ }
+
+ CustomLoggerFinder.CustomLevel getLevel(java.lang.System.Logger logger) {
+ final CustomLoggerFinder.CustomLogger l =
+ (CustomLoggerFinder.CustomLogger)
+ (isSystem ? provider.getLogger(logger.getName(), Thread.class) :
+ provider.getLogger(logger.getName(), LoggerFinderBackendTest.class));
+ return l.level;
+ }
+
+ @Override
+ public List<CustomLoggerFinder.CustomLogRecord> getBackendRecords() {
+ return CustomLoggerFinder.records;
+ }
+
+ @Override
+ public void resetBackendRecords() {
+ CustomLoggerFinder.records.clear();
+ }
+
+ @Override
+ public boolean shouldBeLoggable(Levels level, Level loggerLevel) {
+ return loggerLevel != Level.OFF &&
+ fromLevels(level).ordinal() <= provider.fromJul(loggerLevel).ordinal();
+ }
+
+ @Override
+ public boolean isLoggable(java.lang.System.Logger logger, Level l) {
+ return super.isLoggable(logger, l);
+ }
+
+ @Override
+ public boolean shouldBeLoggable(Level logLevel, Level loggerLevel) {
+ return loggerLevel != Level.OFF &&
+ provider.fromJul(logLevel).ordinal() <= provider.fromJul(loggerLevel).ordinal();
+ }
+
+ @Override // we don't support source class name in our custom provider implementation
+ public String getCallerClassName(Levels level, String clazz) {
+ return null;
+ }
+
+ @Override // we don't support source method name in our custom provider implementation
+ public String getCallerMethodName(Levels level, String method) {
+ return null;
+ }
+
+ @Override // we don't support source class name in our custom provider implementation
+ public String getCallerClassName(MethodInvoker<?,?> logMethod, String clazz) {
+ return null;
+ }
+
+ @Override // we don't support source method name in our custom provider implementation
+ public String getCallerMethodName(MethodInvoker<?,?> logMethod, String method) {
+ return null;
+ }
+
+ @Override
+ public CustomLoggerFinder.CustomLevel getMappedLevel(Object level) {
+ if (level instanceof java.lang.System.Logger.Level) {
+ final int index = ((java.lang.System.Logger.Level)level).ordinal();
+ return CustomLoggerFinder.customLevelMap[index];
+ } else if (level instanceof Level) {
+ return provider.fromJul((Level)level);
+ }
+ return (CustomLoggerFinder.CustomLevel) level;
+ }
+
+ CustomLoggerFinder.CustomLevel fromLevels(Levels level) {
+ switch(level) {
+ case SEVERE:
+ return CustomLoggerFinder.CustomLevel.ERROR;
+ case WARNING:
+ return CustomLoggerFinder.CustomLevel.WARN;
+ case INFO:
+ return CustomLoggerFinder.CustomLevel.INFO;
+ case CONFIG: case FINE:
+ return CustomLoggerFinder.CustomLevel.DEBUG;
+ case FINER: case FINEST:
+ return CustomLoggerFinder.CustomLevel.TRACE;
+ }
+ throw new InternalError("No such level "+level);
+ }
+
+ }
+
+ @Override
+ BackendAdaptor adaptor() {
+ return new CustomBackendAdaptor();
+ }
+
+ }
+
+ public static class CustomBackendTesterFactory extends BackendTesterFactory {
+
+ @Override
+ public BackendTester createBackendTester(boolean isSystem) {
+ return new CustomBackendTester(isSystem);
+ }
+
+ @Override
+ public BackendTester createBackendTester(boolean isSystem,
+ Class<? extends java.lang.System.Logger> restrictedTo) {
+ return new CustomBackendTester(isSystem, restrictedTo);
+ }
+
+ @Override
+ public BackendTester createBackendTester(boolean isSystem,
+ Class<? extends java.lang.System.Logger> restrictedTo,
+ ResourceBundle bundle) {
+ return new CustomBackendTester(isSystem, restrictedTo, bundle);
+ }
+
+ @Override
+ public BackendTester createBackendTester(boolean isSystem,
+ ResourceBundle bundle) {
+ return new CustomBackendTester(isSystem, bundle);
+ }
+ }
+
+ static final Method getLazyLogger;
+ static final Method accessLoggerFinder;
+ static {
+ // jdk.internal.logger.LazyLoggers.getLazyLogger(name, caller);
+ try {
+ Class<?> lazyLoggers = jdk.internal.logger.LazyLoggers.class;
+ getLazyLogger = lazyLoggers.getMethod("getLazyLogger",
+ String.class, Class.class);
+ getLazyLogger.setAccessible(true);
+ Class<?> loggerFinderLoader =
+ Class.forName("java.lang.System$LoggerFinder");
+ accessLoggerFinder = loggerFinderLoader.getDeclaredMethod("accessProvider");
+ accessLoggerFinder.setAccessible(true);
+ } catch (Throwable ex) {
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+ static java.lang.System.Logger getSystemLogger(String name, Class<?> caller) throws Exception {
+ try {
+ return java.lang.System.Logger.class.cast(getLazyLogger.invoke(null, name, caller));
+ } catch (InvocationTargetException x) {
+ Throwable t = x.getTargetException();
+ if (t instanceof Exception) {
+ throw (Exception)t;
+ } else {
+ throw (Error)t;
+ }
+ }
+ }
+ static java.lang.System.Logger getSystemLogger(String name,
+ ResourceBundle bundle, Class<?> caller) throws Exception {
+ try {
+ LoggerFinder provider = LoggerFinder.class.cast(accessLoggerFinder.invoke(null));
+ return provider.getLocalizedLogger(name, bundle, caller);
+ } catch (InvocationTargetException x) {
+ Throwable t = x.getTargetException();
+ if (t instanceof Exception) {
+ throw (Exception)t;
+ } else {
+ throw (Error)t;
+ }
+ }
+ }
+
+ // Change this to 'true' to get more traces...
+ public static boolean verbose = false;
+
+ public static void main(String[] argv) throws Exception {
+
+ final AtomicInteger nb = new AtomicInteger(0);
+ final boolean hidesProvider = Boolean.getBoolean("test.logger.hidesProvider");
+ System.out.println(ClassLoader.getSystemClassLoader());
+ final BackendTesterFactory factory;
+ if (java.lang.System.LoggerFinder.getLoggerFinder() instanceof CustomLoggerFinder) {
+ if (hidesProvider) {
+ System.err.println("Custom backend "
+ + java.lang.System.LoggerFinder.getLoggerFinder()
+ + " should have been hidden!");
+ throw new RuntimeException(
+ "Custom backend should have been hidden: "
+ + "check value of java.system.class.loader property");
+ }
+ System.out.println("Using custom backend");
+ factory = new CustomBackendTesterFactory();
+ } else {
+ if (!hidesProvider) {
+ System.err.println("Default JUL backend "
+ + java.lang.System.LoggerFinder.getLoggerFinder()
+ + " should have been hidden!");
+ throw new RuntimeException(
+ "Default JUL backend should have been hidden: "
+ + "check value of java.system.class.loader property");
+ }
+ System.out.println("Using JUL backend");
+ factory = new JULBackendTesterFactory();
+ }
+
+ testBackend(nb, factory);
+ }
+
+ public static void testBackend(AtomicInteger nb, BackendTesterFactory factory) throws Exception {
+
+ // Tests all level specifics methods with loggers configured with
+ // all possible levels and loggers obtained with all possible
+ // entry points from LoggerFactory and JdkLoggerFactory, with
+ // JUL as backend.
+
+ // Test a simple application logger with JUL backend
+ final BackendTester tester = factory.createBackendTester(false);
+ final java.lang.System.Logger logger =
+ java.lang.System.LoggerFinder.getLoggerFinder()
+ .getLogger("foo", LoggerFinderBackendTest.class);
+
+ testLogger(tester, logger, nb);
+
+ // Test a simple system logger with JUL backend
+ final java.lang.System.Logger system =
+ java.lang.System.LoggerFinder.getLoggerFinder()
+ .getLogger("bar", Thread.class);
+ final BackendTester systemTester = factory.createBackendTester(true);
+ testLogger(systemTester, system, nb);
+
+ // Test a localized application logger with null resource bundle and
+ // JUL backend
+ final java.lang.System.Logger noBundleLogger =
+ java.lang.System.LoggerFinder.getLoggerFinder()
+ .getLocalizedLogger("baz", null, LoggerFinderBackendTest.class);
+ final BackendTester noBundleTester =
+ factory.createBackendTester(false, spiLoggerClass);
+ testLogger(noBundleTester, noBundleLogger, nb);
+
+ // Test a localized system logger with null resource bundle and JUL
+ // backend
+ final java.lang.System.Logger noBundleSysLogger =
+ java.lang.System.LoggerFinder.getLoggerFinder()
+ .getLocalizedLogger("oof", null, Thread.class);
+ final BackendTester noBundleSysTester =
+ factory.createBackendTester(true, spiLoggerClass);
+ testLogger(noBundleSysTester, noBundleSysLogger, nb);
+
+ // Test a localized application logger with null resource bundle and
+ // JUL backend
+ try {
+ System.getLogger("baz", null);
+ throw new RuntimeException("Expected NullPointerException not thrown");
+ } catch (NullPointerException x) {
+ System.out.println("System.Loggers.getLogger(\"baz\", null): got expected " + x);
+ }
+ final java.lang.System.Logger noBundleExtensionLogger =
+ getSystemLogger("baz", null, LoggerFinderBackendTest.class);
+ final BackendTester noBundleExtensionTester =
+ factory.createBackendTester(false, jdkLoggerClass);
+ testLogger(noBundleExtensionTester, noBundleExtensionLogger, nb);
+
+ // Test a simple system logger with JUL backend
+ final java.lang.System.Logger sysExtensionLogger =
+ getSystemLogger("oof", Thread.class);
+ final BackendTester sysExtensionTester =
+ factory.createBackendTester(true, jdkLoggerClass);
+ testLogger(sysExtensionTester, sysExtensionLogger, nb);
+
+ // Test a localized system logger with null resource bundle and JUL
+ // backend
+ final java.lang.System.Logger noBundleSysExtensionLogger =
+ getSystemLogger("oof", null, Thread.class);
+ final BackendTester noBundleSysExtensionTester =
+ factory.createBackendTester(true, jdkLoggerClass);
+ testLogger(noBundleSysExtensionTester, noBundleSysExtensionLogger, nb);
+
+ // Test a localized application logger converted to JDK with null
+ // resource bundle and JUL backend
+ final java.lang.System.Logger noBundleConvertedLogger =
+ (java.lang.System.Logger)
+ sun.util.logging.PlatformLogger.Bridge.convert(noBundleLogger);
+ final BackendTester noBundleJdkTester = factory.createBackendTester(false);
+ testLogger(noBundleJdkTester, noBundleConvertedLogger, nb);
+
+ // Test a localized system logger converted to JDK with null resource
+ // bundle and JUL backend
+ final java.lang.System.Logger noBundleConvertedSysLogger =
+ (java.lang.System.Logger)
+ sun.util.logging.PlatformLogger.Bridge.convert(noBundleSysLogger);
+ final BackendTester noBundleJdkSysTester = factory.createBackendTester(true);
+ testLogger(noBundleJdkSysTester, noBundleConvertedSysLogger, nb);
+
+ // Test a localized application logger with resource bundle and JUL
+ // backend
+ final ResourceBundle bundle =
+ ResourceBundle.getBundle(ResourceBundeLocalized.class.getName());
+ final java.lang.System.Logger bundleLogger =
+ java.lang.System.LoggerFinder.getLoggerFinder()
+ .getLocalizedLogger("toto", bundle, LoggerFinderBackendTest.class);
+ final BackendTester bundleTester =
+ factory.createBackendTester(false, spiLoggerClass, bundle);
+ testLogger(bundleTester, bundleLogger, nb);
+
+ // Test a localized system logger with resource bundle and JUL backend
+ final java.lang.System.Logger bundleSysLogger =
+ java.lang.System.LoggerFinder.getLoggerFinder()
+ .getLocalizedLogger("titi", bundle, Thread.class);
+ final BackendTester bundleSysTester =
+ factory.createBackendTester(true, spiLoggerClass, bundle);
+ testLogger(bundleSysTester, bundleSysLogger, nb);
+
+ // Test a localized Jdk application logger with resource bundle and JUL
+ // backend
+ final java.lang.System.Logger bundleExtensionLogger =
+ System.getLogger("tita", bundle);
+ final BackendTester bundleExtensionTester =
+ factory.createBackendTester(false, jdkLoggerClass, bundle);
+ testLogger(bundleExtensionTester, bundleExtensionLogger, nb);
+
+ // Test a localized Jdk system logger with resource bundle and JUL
+ // backend
+ final java.lang.System.Logger bundleExtensionSysLogger =
+ getSystemLogger("titu", bundle, Thread.class);
+ final BackendTester bundleExtensionSysTester =
+ factory.createBackendTester(true, jdkLoggerClass, bundle);
+ testLogger(bundleExtensionSysTester, bundleExtensionSysLogger, nb);
+
+ // Test a localized application logger converted to JDK with resource
+ // bundle and JUL backend
+ final BackendTester bundleJdkTester =
+ factory.createBackendTester(false, bundle);
+ final java.lang.System.Logger bundleConvertedLogger =
+ (java.lang.System.Logger)
+ sun.util.logging.PlatformLogger.Bridge.convert(bundleLogger);
+ testLogger(bundleJdkTester, bundleConvertedLogger, nb);
+
+ // Test a localized Jdk system logger converted to JDK with resource
+ // bundle and JUL backend
+ final BackendTester bundleJdkSysTester =
+ factory.createBackendTester(true, bundle);
+ final java.lang.System.Logger bundleConvertedSysLogger =
+ (java.lang.System.Logger)
+ sun.util.logging.PlatformLogger.Bridge.convert(bundleSysLogger);
+ testLogger(bundleJdkSysTester, bundleConvertedSysLogger, nb);
+
+ // Now need to add tests for all the log/logp/logrb methods...
+
+ }
+
+ private static class FooObj {
+ final String s;
+ FooObj(String s) {
+ this.s = s;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() +": "+s;
+ }
+
+ }
+
+ public static void testLogger(BackendTester tester,
+ java.lang.System.Logger spiLogger, AtomicInteger nb) {
+
+ // Test all level-specific method forms:
+ // fatal(...) error(...) severe(...) etc...
+ java.lang.System.Logger jdkLogger = tester.convert(spiLogger);
+ for (Levels l : Levels.values()) {
+ java.lang.System.Logger logger =
+ l.definingClass.equals(spiLoggerClass) ? spiLogger : jdkLogger;
+ tester.testLevel(l, logger, l.method + "[" + logger.getName()+ "]-"
+ + nb.incrementAndGet());
+ tester.testLevel(l, logger, l.method + "[" + logger.getName()+ "]-"
+ + nb.incrementAndGet(),
+ bundleParam);
+ final int nbb = nb.incrementAndGet();
+ tester.testLevel(l, logger, () -> l.method + "[" + logger.getName()
+ + "]-" + nbb);
+ }
+ for (Levels l : Levels.values()) {
+ java.lang.System.Logger logger =
+ l.definingClass.equals(spiLoggerClass) ? spiLogger : jdkLogger;
+ tester.testLevel(l, logger,
+ l.method + "[" + logger.getName()+ "]({0},{1})-"
+ + nb.incrementAndGet(),
+ "One", "Two");
+ tester.testLevel(l, logger,
+ l.method + "[" + logger.getName()+ "]({0},{1})-"
+ + nb.incrementAndGet(),
+ bundleParam, "One", "Two");
+ }
+ final Throwable thrown = new RuntimeException("Test");
+ for (Levels l : Levels.values()) {
+ java.lang.System.Logger logger =
+ l.definingClass.equals(spiLoggerClass) ? spiLogger : jdkLogger;
+ tester.testLevel(l, logger, l.method + "[" + logger.getName()+ "]-"
+ + nb.incrementAndGet(),
+ thrown);
+ tester.testLevel(l, logger, l.method + "[" + logger.getName()+ "]-"
+ + nb.incrementAndGet(),
+ bundleParam, thrown);
+ final int nbb = nb.incrementAndGet();
+ tester.testLevel(l, logger, ()->l.method + "[" + logger.getName()+ "]-"
+ + nbb, thrown);
+ }
+
+ java.lang.System.Logger logger = jdkLogger;
+
+ // test System.Logger methods
+ tester.testSpiLog(logger, "[" + logger.getName()+ "]-"
+ + nb.incrementAndGet());
+ tester.testSpiLog(logger, bundleParam, "[" + logger.getName()+ "]-"
+ + nb.incrementAndGet());
+ tester.testSpiLog(logger, "[" + logger.getName()+ "]-({0},{1})"
+ + nb.incrementAndGet(), "One", "Two");
+ tester.testSpiLog(logger, bundleParam, "[" + logger.getName()+ "]-({0},{1})"
+ + nb.incrementAndGet(), "One", "Two");
+ tester.testSpiLog(logger, "[" + logger.getName()+ "]-"
+ + nb.incrementAndGet(), thrown);
+ tester.testSpiLog(logger, bundleParam, "[" + logger.getName()+ "]-"
+ + nb.incrementAndGet(), thrown);
+ final int nbb01 = nb.incrementAndGet();
+ tester.testSpiLog(logger, () -> "[" + logger.getName()+ "]-" + nbb01);
+ final int nbb02 = nb.incrementAndGet();
+ tester.testSpiLog(logger, thrown, () -> "[" + logger.getName()+ "]-" + nbb02);
+ final int nbb03 = nb.incrementAndGet();
+ tester.testSpiLog(logger, new FooObj("[" + logger.getName()+ "]-" + nbb03));
+
+ // Test all log method forms:
+ // jdk.internal.logging.Logger.log(...)
+ tester.testLog(logger, "[" + logger.getName()+ "]-"
+ + nb.incrementAndGet());
+ tester.testLogrb(logger, bundleParam, "[" + logger.getName()+ "]-"
+ + nb.incrementAndGet());
+ tester.testLog(logger, "[" + logger.getName()+ "]-({0},{1})"
+ + nb.incrementAndGet(), "One", "Two");
+ tester.testLogrb(logger, bundleParam, "[" + logger.getName()+ "]-({0},{1})"
+ + nb.incrementAndGet(), "One", "Two");
+ tester.testLog(logger, "[" + logger.getName()+ "]-"
+ + nb.incrementAndGet(), thrown);
+ tester.testLogrb(logger, bundleParam, "[" + logger.getName()+ "]-"
+ + nb.incrementAndGet(), thrown);
+ final int nbb1 = nb.incrementAndGet();
+ tester.testLog(logger, () -> "[" + logger.getName()+ "]-" + nbb1);
+ final int nbb2 = nb.incrementAndGet();
+ tester.testLog(logger, thrown, () -> "[" + logger.getName()+ "]-" + nbb2);
+
+ // Test all logp method forms
+ // jdk.internal.logging.Logger.logp(...)
+ tester.testLogp(logger, "clazz" + nb.incrementAndGet(),
+ "method" + nb.incrementAndGet(),
+ "[" + logger.getName()+ "]-"
+ + nb.incrementAndGet());
+ tester.testLogrb(logger, "clazz" + nb.incrementAndGet(),
+ "method" + nb.incrementAndGet(), bundleParam,
+ "[" + logger.getName()+ "]-"
+ + nb.incrementAndGet());
+ tester.testLogp(logger, "clazz" + nb.incrementAndGet(),
+ "method" + nb.incrementAndGet(),
+ "[" + logger.getName()+ "]-({0},{1})"
+ + nb.incrementAndGet(), "One", "Two");
+ tester.testLogrb(logger, "clazz" + nb.incrementAndGet(),
+ "method" + nb.incrementAndGet(), bundleParam,
+ "[" + logger.getName()+ "]-({0},{1})"
+ + nb.incrementAndGet(), "One", "Two");
+ tester.testLogp(logger, "clazz" + nb.incrementAndGet(),
+ "method" + nb.incrementAndGet(),
+ "[" + logger.getName()+ "]-"
+ + nb.incrementAndGet(), thrown);
+ tester.testLogrb(logger, "clazz" + nb.incrementAndGet(),
+ "method" + nb.incrementAndGet(), bundleParam,
+ "[" + logger.getName()+ "]-"
+ + nb.incrementAndGet(), thrown);
+ final int nbb3 = nb.incrementAndGet();
+ tester.testLogp(logger, "clazz" + nb.incrementAndGet(),
+ "method" + nb.incrementAndGet(),
+ () -> "[" + logger.getName()+ "]-" + nbb3);
+ final int nbb4 = nb.incrementAndGet();
+ tester.testLogp(logger, "clazz" + nb.incrementAndGet(),
+ "method" + nb.incrementAndGet(),
+ thrown, () -> "[" + logger.getName()+ "]-" + nbb4);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/backend/META-INF/services/java.lang.System$LoggerFinder Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,2 @@
+LoggerFinderBackendTest$CustomLoggerFinder
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/backend/SystemClassLoader.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.lang.System.LoggerFinder;
+
+/**
+ * A custom class loader which can hide the registered LoggerProvider
+ * depending on the value of a test.logger.hidesProvider system property.
+ * @author danielfuchs
+ */
+public class SystemClassLoader extends ClassLoader {
+
+ final public boolean hidesProvider;
+
+ public SystemClassLoader() {
+ hidesProvider = Boolean.getBoolean("test.logger.hidesProvider");
+ }
+ public SystemClassLoader(ClassLoader parent) {
+ super(parent);
+ hidesProvider = Boolean.getBoolean("test.logger.hidesProvider");
+ }
+
+ boolean accept(String name) {
+ final boolean res = !name.endsWith(LoggerFinder.class.getName());
+ if (res == false) {
+ System.out.println("Hiding " + name);
+ }
+ return res;
+ }
+
+ @Override
+ public URL getResource(String name) {
+ if (hidesProvider && !accept(name)) {
+ return null;
+ } else {
+ return super.getResource(name);
+ }
+ }
+
+ class Enumerator implements Enumeration<URL> {
+ final Enumeration<URL> enumeration;
+ volatile URL next;
+ Enumerator(Enumeration<URL> enumeration) {
+ this.enumeration = enumeration;
+ }
+
+ @Override
+ public boolean hasMoreElements() {
+ if (next != null) return true;
+ if (!enumeration.hasMoreElements()) return false;
+ if (hidesProvider == false) return true;
+ next = enumeration.nextElement();
+ if (accept(next.getPath())) return true;
+ next = null;
+ return hasMoreElements();
+ }
+
+ @Override
+ public URL nextElement() {
+ final URL res = next == null ? enumeration.nextElement() : next;
+ next = null;
+ if (hidesProvider == false || accept(res.getPath())) return res;
+ return nextElement();
+ }
+ }
+
+ @Override
+ public Enumeration<URL> getResources(String name) throws IOException {
+ final Enumeration<URL> enumeration = super.getResources(name);
+ return hidesProvider ? new Enumerator(enumeration) : enumeration;
+ }
+
+
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/jdk/DefaultLoggerBridgeTest/DefaultLoggerBridgeTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,850 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.security.AccessControlException;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.ResourceBundle;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Supplier;
+import java.util.logging.Handler;
+import java.util.logging.LogManager;
+import sun.util.logging.PlatformLogger;
+import java.util.logging.LogRecord;
+import java.lang.System.LoggerFinder;
+import java.lang.System.Logger;
+import java.util.stream.Stream;
+import sun.util.logging.internal.LoggingProviderImpl;
+
+/**
+ * @test
+ * @bug 8140364
+ * @summary JDK implementation specific unit test for JDK internal artifacts.
+ * Tests all internal bridge methods with the default LoggerFinder
+ * JUL backend.
+ * @modules java.base/sun.util.logging
+ * java.base/jdk.internal.logger
+ * java.logging/sun.util.logging.internal
+ * @run main/othervm DefaultLoggerBridgeTest
+ * @author danielfuchs
+ */
+public class DefaultLoggerBridgeTest {
+
+ final static AtomicLong sequencer = new AtomicLong();
+ final static boolean VERBOSE = false;
+ static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+ static final ThreadLocal<AtomicBoolean> allowAccess = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+ static final ThreadLocal<AtomicBoolean> allowAll = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+
+ public static final Queue<LogEvent> eventQueue = new ArrayBlockingQueue<>(128);
+
+ public static final class LogEvent implements Cloneable {
+
+ public LogEvent() {
+ this(sequencer.getAndIncrement());
+ }
+
+ LogEvent(long sequenceNumber) {
+ this.sequenceNumber = sequenceNumber;
+ }
+
+ long sequenceNumber;
+ boolean isLoggable;
+ String loggerName;
+ java.util.logging.Level level;
+ ResourceBundle bundle;
+ Throwable thrown;
+ Object[] args;
+ String msg;
+ String className;
+ String methodName;
+
+ Object[] toArray() {
+ return new Object[] {
+ sequenceNumber,
+ isLoggable,
+ loggerName,
+ level,
+ bundle,
+ thrown,
+ args,
+ msg,
+ className,
+ methodName,
+ };
+ }
+
+ @Override
+ public String toString() {
+ return Arrays.deepToString(toArray());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof LogEvent
+ && Objects.deepEquals(this.toArray(), ((LogEvent)obj).toArray());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(toArray());
+ }
+
+ public LogEvent cloneWith(long sequenceNumber)
+ throws CloneNotSupportedException {
+ LogEvent cloned = (LogEvent)super.clone();
+ cloned.sequenceNumber = sequenceNumber;
+ return cloned;
+ }
+
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ java.util.logging.Level level, ResourceBundle bundle,
+ String key, Throwable thrown, Object... params) {
+ return LogEvent.of(sequenceNumber, isLoggable, name,
+ DefaultLoggerBridgeTest.class.getName(),
+ "testLogger", level, bundle, key,
+ thrown, params);
+ }
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ String className, String methodName,
+ java.util.logging.Level level, ResourceBundle bundle,
+ String key, Throwable thrown, Object... params) {
+ LogEvent evt = new LogEvent(sequenceNumber);
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = params;
+ evt.bundle = bundle;
+ evt.thrown = thrown;
+ evt.msg = key;
+ evt.isLoggable = isLoggable;
+ evt.className = className;
+ evt.methodName = methodName;
+ return evt;
+ }
+
+ }
+
+ static final java.util.logging.Level[] julLevels = {
+ java.util.logging.Level.ALL,
+ java.util.logging.Level.FINEST,
+ java.util.logging.Level.FINER,
+ java.util.logging.Level.FINE,
+ java.util.logging.Level.CONFIG,
+ java.util.logging.Level.INFO,
+ java.util.logging.Level.WARNING,
+ java.util.logging.Level.SEVERE,
+ java.util.logging.Level.OFF,
+ };
+
+
+ public static class MyBundle extends ResourceBundle {
+
+ final ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
+
+ @Override
+ protected Object handleGetObject(String key) {
+ if (key.contains(" (translated)")) {
+ throw new RuntimeException("Unexpected key: " + key);
+ }
+ return map.computeIfAbsent(key, k -> k + " (translated)");
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ return Collections.enumeration(map.keySet());
+ }
+
+ }
+
+ public static class MyHandler extends Handler {
+
+ @Override
+ public java.util.logging.Level getLevel() {
+ return java.util.logging.Level.ALL;
+ }
+
+ @Override
+ public void publish(LogRecord record) {
+ eventQueue.add(LogEvent.of(sequencer.getAndIncrement(),
+ true, record.getLoggerName(),
+ record.getSourceClassName(),
+ record.getSourceMethodName(),
+ record.getLevel(),
+ record.getResourceBundle(), record.getMessage(),
+ record.getThrown(), record.getParameters()));
+ }
+ @Override
+ public void flush() {
+ }
+ @Override
+ public void close() throws SecurityException {
+ }
+
+ }
+
+ public static class MyLoggerBundle extends MyBundle {
+
+ }
+
+ static PlatformLogger.Bridge convert(Logger logger) {
+ boolean old = allowAccess.get().get();
+ allowAccess.get().set(true);
+ try {
+ return PlatformLogger.Bridge.convert(logger);
+ } finally {
+ allowAccess.get().set(old);
+ }
+ }
+
+ static Logger getLogger(String name, Class<?> caller) {
+ boolean old = allowAccess.get().get();
+ allowAccess.get().set(true);
+ try {
+ return jdk.internal.logger.LazyLoggers.getLogger(name, caller);
+ } finally {
+ allowAccess.get().set(old);
+ }
+ }
+
+ static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS};
+
+ static void setSecurityManager() {
+ if (System.getSecurityManager() == null) {
+ Policy.setPolicy(new SimplePolicy(allowControl, allowAccess, allowAll));
+ System.setSecurityManager(new SecurityManager());
+ }
+ }
+
+ public static void main(String[] args) {
+ if (args.length == 0)
+ args = new String[] {
+ "NOSECURITY",
+ "NOPERMISSIONS",
+ "WITHPERMISSIONS"
+ };
+
+ Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> {
+ LoggerFinder provider;
+ switch (testCase) {
+ case NOSECURITY:
+ System.out.println("\n*** Without Security Manager\n");
+ test(true);
+ System.out.println("Tetscase count: " + sequencer.get());
+ break;
+ case NOPERMISSIONS:
+ System.out.println("\n*** With Security Manager, without permissions\n");
+ setSecurityManager();
+ test(false);
+ System.out.println("Tetscase count: " + sequencer.get());
+ break;
+ case WITHPERMISSIONS:
+ System.out.println("\n*** With Security Manager, with control permission\n");
+ setSecurityManager();
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ test(true);
+ } finally {
+ allowControl.get().set(control);
+ }
+ break;
+ default:
+ throw new RuntimeException("Unknown test case: " + testCase);
+ }
+ });
+ System.out.println("\nPASSED: Tested " + sequencer.get() + " cases.");
+ }
+
+ public static void test(boolean hasRequiredPermissions) {
+
+ ResourceBundle loggerBundle =
+ ResourceBundle.getBundle(MyLoggerBundle.class.getName());
+ final Map<Object, String> loggerDescMap = new HashMap<>();
+
+ Logger sysLogger1a = getLogger("foo", Thread.class);
+ loggerDescMap.put(sysLogger1a, "jdk.internal.logger.LazyLoggers.getLogger(\"foo\", Thread.class)");
+
+ Logger appLogger1 = System.getLogger("foo");
+ loggerDescMap.put(appLogger1, "System.getLogger(\"foo\")");
+
+ LoggerFinder provider;
+ try {
+ provider = LoggerFinder.getLoggerFinder();
+ if (!hasRequiredPermissions) {
+ throw new RuntimeException("Expected exception not raised");
+ }
+ } catch (AccessControlException x) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected permission check", x);
+ }
+ if (!SimplePolicy.LOGGERFINDER_PERMISSION.equals(x.getPermission())) {
+ throw new RuntimeException("Unexpected permission in exception: " + x, x);
+ }
+ final boolean control = allowControl.get().get();
+ try {
+ allowControl.get().set(true);
+ provider = LoggerFinder.getLoggerFinder();
+ } finally {
+ allowControl.get().set(control);
+ }
+ }
+
+ Logger sysLogger1b = null;
+ try {
+ sysLogger1b = provider.getLogger("foo", Thread.class);
+ if (sysLogger1b != sysLogger1a) {
+ loggerDescMap.put(sysLogger1b, "provider.getLogger(\"foo\", Thread.class)");
+ }
+ if (!hasRequiredPermissions) {
+ throw new RuntimeException("Managed to obtain a system logger without permission");
+ }
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(SimplePolicy.LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ System.out.println("Got expected exception for system logger: " + acx);
+ }
+
+ Logger appLogger2 = System.getLogger("foo", loggerBundle);
+ loggerDescMap.put(appLogger2, "System.getLogger(\"foo\", loggerBundle)");
+
+ if (appLogger2 == appLogger1) {
+ throw new RuntimeException("identical loggers");
+ }
+
+ Logger sysLogger2 = null;
+ try {
+ sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class);
+ loggerDescMap.put(sysLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, Thread.class)");
+ if (!hasRequiredPermissions) {
+ throw new RuntimeException("Managed to obtain a system logger without permission");
+ }
+ } catch (AccessControlException acx) {
+ if (hasRequiredPermissions) {
+ throw new RuntimeException("Unexpected security exception: ", acx);
+ }
+ if (!acx.getPermission().equals(SimplePolicy.LOGGERFINDER_PERMISSION)) {
+ throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
+ }
+ System.out.println("Got expected exception for localized system logger: " + acx);
+ }
+ if (hasRequiredPermissions && appLogger2 == sysLogger2) {
+ throw new RuntimeException("identical loggers");
+ }
+ if (hasRequiredPermissions && sysLogger2 == sysLogger1a) {
+ throw new RuntimeException("identical loggers");
+ }
+
+ final java.util.logging.Logger appSink;
+ final java.util.logging.Logger sysSink;
+ final MyHandler appHandler;
+ final MyHandler sysHandler;
+ final boolean old = allowAll.get().get();
+ allowAll.get().set(true);
+ try {
+ sysSink = LoggingProviderImpl.getLogManagerAccess().demandLoggerFor(
+ LogManager.getLogManager(), "foo", Thread.class);
+ appSink = LoggingProviderImpl.getLogManagerAccess().demandLoggerFor(
+ LogManager.getLogManager(), "foo", DefaultLoggerBridgeTest.class);
+ if (appSink == sysSink) {
+ throw new RuntimeException("identical backend loggers");
+ }
+ appSink.addHandler(appHandler = new MyHandler());
+ sysSink.addHandler(sysHandler = new MyHandler());
+ appSink.setUseParentHandlers(VERBOSE);
+ sysSink.setUseParentHandlers(VERBOSE);
+ } finally {
+ allowAll.get().set(old);
+ }
+
+ try {
+ testLogger(provider, loggerDescMap, "foo", null, convert(sysLogger1a), sysSink);
+ testLogger(provider, loggerDescMap, "foo", null, convert(appLogger1), appSink);
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, convert(appLogger2), appSink);
+ if (sysLogger1b != null && sysLogger1b != sysLogger1a) {
+ testLogger(provider, loggerDescMap, "foo", null, convert(sysLogger1b), sysSink);
+ }
+ if (sysLogger2 != null) {
+ testLogger(provider, loggerDescMap, "foo", loggerBundle, convert(sysLogger2), sysSink);
+ }
+ } finally {
+ allowAll.get().set(true);
+ try {
+ appSink.removeHandler(appHandler);
+ sysSink.removeHandler(sysHandler);
+ } finally {
+ allowAll.get().set(old);
+ }
+ }
+ }
+
+ public static class Foo {
+
+ }
+
+ static void verbose(String msg) {
+ if (VERBOSE) {
+ System.out.println(msg);
+ }
+ }
+
+ static void checkLogEvent(LoggerFinder provider, String desc,
+ LogEvent expected) {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+
+ static void checkLogEvent(LoggerFinder provider, String desc,
+ LogEvent expected, boolean expectNotNull) {
+ LogEvent actual = eventQueue.poll();
+ if (actual == null && !expectNotNull) return;
+ if (actual != null && !expectNotNull) {
+ throw new RuntimeException("Unexpected log event found for " + desc
+ + "\n\tgot: " + actual);
+ }
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+
+ static void setLevel(java.util.logging.Logger sink, java.util.logging.Level loggerLevel) {
+ boolean before = allowAll.get().get();
+ try {
+ allowAll.get().set(true);
+ sink.setLevel(loggerLevel);
+ } finally {
+ allowAll.get().set(before);
+ }
+ }
+
+ static sun.util.logging.PlatformLogger.Level toPlatformLevel(java.util.logging.Level level) {
+ boolean old = allowAccess.get().get();
+ allowAccess.get().set(true);
+ try {
+ return sun.util.logging.PlatformLogger.Level.valueOf(level.getName());
+ } finally {
+ allowAccess.get().set(old);
+ }
+ }
+
+ // Calls the methods defined on LogProducer and verify the
+ // parameters received by the underlying logger.
+ private static void testLogger(LoggerFinder provider,
+ Map<Object, String> loggerDescMap,
+ String name,
+ ResourceBundle loggerBundle,
+ PlatformLogger.Bridge logger,
+ java.util.logging.Logger sink) {
+
+ if (loggerDescMap.get(logger) == null) {
+ throw new RuntimeException("Missing description for " + logger);
+ }
+ System.out.println("Testing " + loggerDescMap.get(logger) + " [" + logger + "]");
+ final java.util.logging.Level OFF = java.util.logging.Level.OFF;
+
+ Foo foo = new Foo();
+ String fooMsg = foo.toString();
+ System.out.println("\tlogger.log(messageLevel, fooMsg)");
+ System.out.println("\tlogger.<level>(fooMsg)");
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (java.util.logging.Level messageLevel :julLevels) {
+ String desc = "logger.log(messageLevel, fooMsg): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, loggerBundle,
+ fooMsg, (Throwable)null, (Object[])null);
+ logger.log(toPlatformLevel(messageLevel), fooMsg);
+ checkLogEvent(provider, desc, expected, expected.isLoggable);
+ }
+ }
+
+ Supplier<String> supplier = new Supplier<String>() {
+ @Override
+ public String get() {
+ return this.toString();
+ }
+ };
+ System.out.println("\tlogger.log(messageLevel, supplier)");
+ System.out.println("\tlogger.<level>(supplier)");
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (java.util.logging.Level messageLevel :julLevels) {
+ String desc = "logger.log(messageLevel, supplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, null,
+ supplier.get(), (Throwable)null, (Object[])null);
+ logger.log(toPlatformLevel(messageLevel), supplier);
+ checkLogEvent(provider, desc, expected, expected.isLoggable);
+ }
+ }
+
+ String format = "two params [{1} {2}]";
+ Object arg1 = foo;
+ Object arg2 = fooMsg;
+ System.out.println("\tlogger.log(messageLevel, format, arg1, arg2)");
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (java.util.logging.Level messageLevel :julLevels) {
+ String desc = "logger.log(messageLevel, format, foo, fooMsg): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, loggerBundle,
+ format, (Throwable)null, arg1, arg2);
+ logger.log(toPlatformLevel(messageLevel), format, arg1, arg2);
+ checkLogEvent(provider, desc, expected, expected.isLoggable);
+ }
+ }
+
+ Throwable thrown = new Exception("OK: log me!");
+ System.out.println("\tlogger.log(messageLevel, fooMsg, thrown)");
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (java.util.logging.Level messageLevel :julLevels) {
+ String desc = "logger.log(messageLevel, fooMsg, thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, loggerBundle,
+ fooMsg, thrown, (Object[])null);
+ logger.log(toPlatformLevel(messageLevel), fooMsg, thrown);
+ checkLogEvent(provider, desc, expected, expected.isLoggable);
+ }
+ }
+
+ System.out.println("\tlogger.log(messageLevel, thrown, supplier)");
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (java.util.logging.Level messageLevel :julLevels) {
+ String desc = "logger.log(messageLevel, thrown, supplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, null,
+ supplier.get(), thrown, (Object[])null);
+ logger.log(toPlatformLevel(messageLevel), thrown, supplier);
+ checkLogEvent(provider, desc, expected, expected.isLoggable);
+ }
+ }
+
+ String sourceClass = "blah.Blah";
+ String sourceMethod = "blih";
+ System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, fooMsg)");
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (java.util.logging.Level messageLevel :julLevels) {
+ String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, fooMsg): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, sourceClass, sourceMethod, messageLevel, loggerBundle,
+ fooMsg, (Throwable)null, (Object[])null);
+ logger.logp(toPlatformLevel(messageLevel), sourceClass, sourceMethod, fooMsg);
+ checkLogEvent(provider, desc, expected, expected.isLoggable);
+ }
+ }
+
+ System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, supplier)");
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (java.util.logging.Level messageLevel :julLevels) {
+ String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, supplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, sourceClass, sourceMethod, messageLevel, null,
+ supplier.get(), (Throwable)null, (Object[])null);
+ logger.logp(toPlatformLevel(messageLevel), sourceClass, sourceMethod, supplier);
+ checkLogEvent(provider, desc, expected, expected.isLoggable);
+ }
+ }
+
+ System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, format, arg1, arg2)");
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (java.util.logging.Level messageLevel :julLevels) {
+ String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, format, arg1, arg2): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, sourceClass, sourceMethod, messageLevel, loggerBundle,
+ format, (Throwable)null, arg1, arg2);
+ logger.logp(toPlatformLevel(messageLevel), sourceClass, sourceMethod, format, arg1, arg2);
+ checkLogEvent(provider, desc, expected, expected.isLoggable);
+ }
+ }
+
+ System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, fooMsg, thrown)");
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (java.util.logging.Level messageLevel :julLevels) {
+ String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, fooMsg, thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, sourceClass, sourceMethod, messageLevel, loggerBundle,
+ fooMsg, thrown, (Object[])null);
+ logger.logp(toPlatformLevel(messageLevel), sourceClass, sourceMethod, fooMsg, thrown);
+ checkLogEvent(provider, desc, expected, expected.isLoggable);
+ }
+ }
+
+ System.out.println("\tlogger.logp(messageLevel, sourceClass, sourceMethod, thrown, supplier)");
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (java.util.logging.Level messageLevel :julLevels) {
+ String desc = "logger.logp(messageLevel, sourceClass, sourceMethod, thrown, supplier): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, sourceClass, sourceMethod, messageLevel, null,
+ supplier.get(), thrown, (Object[])null);
+ logger.logp(toPlatformLevel(messageLevel), sourceClass, sourceMethod, thrown, supplier);
+ checkLogEvent(provider, desc, expected, expected.isLoggable);
+ }
+ }
+
+ ResourceBundle bundle = ResourceBundle.getBundle(MyBundle.class.getName());
+ System.out.println("\tlogger.logrb(messageLevel, bundle, format, arg1, arg2)");
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (java.util.logging.Level messageLevel :julLevels) {
+ String desc = "logger.logrb(messageLevel, bundle, format, arg1, arg2): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, bundle,
+ format, (Throwable)null, arg1, arg2);
+ logger.logrb(toPlatformLevel(messageLevel), bundle, format, arg1, arg2);
+ checkLogEvent(provider, desc, expected, expected.isLoggable);
+ }
+ }
+
+ System.out.println("\tlogger.logrb(messageLevel, bundle, msg, thrown)");
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (java.util.logging.Level messageLevel :julLevels) {
+ String desc = "logger.logrb(messageLevel, bundle, msg, thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, bundle,
+ fooMsg, thrown, (Object[])null);
+ logger.logrb(toPlatformLevel(messageLevel), bundle, fooMsg, thrown);
+ checkLogEvent(provider, desc, expected, expected.isLoggable);
+ }
+ }
+
+ System.out.println("\tlogger.logrb(messageLevel, sourceClass, sourceMethod, bundle, format, arg1, arg2)");
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (java.util.logging.Level messageLevel :julLevels) {
+ String desc = "logger.logrb(messageLevel, sourceClass, sourceMethod, bundle, format, arg1, arg2): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, sourceClass, sourceMethod, messageLevel, bundle,
+ format, (Throwable)null, arg1, arg2);
+ logger.logrb(toPlatformLevel(messageLevel), sourceClass, sourceMethod, bundle, format, arg1, arg2);
+ checkLogEvent(provider, desc, expected, expected.isLoggable);
+ }
+ }
+
+ System.out.println("\tlogger.logrb(messageLevel, sourceClass, sourceMethod, bundle, msg, thrown)");
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (java.util.logging.Level messageLevel :julLevels) {
+ String desc = "logger.logrb(messageLevel, sourceClass, sourceMethod, bundle, msg, thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, sourceClass, sourceMethod, messageLevel, bundle,
+ fooMsg, thrown, (Object[])null);
+ logger.logrb(toPlatformLevel(messageLevel), sourceClass, sourceMethod, bundle, fooMsg, thrown);
+ checkLogEvent(provider, desc, expected, expected.isLoggable);
+ }
+ }
+ }
+
+ final static class PermissionsBuilder {
+ final Permissions perms;
+ public PermissionsBuilder() {
+ this(new Permissions());
+ }
+ public PermissionsBuilder(Permissions perms) {
+ this.perms = perms;
+ }
+ public PermissionsBuilder add(Permission p) {
+ perms.add(p);
+ return this;
+ }
+ public PermissionsBuilder addAll(PermissionCollection col) {
+ if (col != null) {
+ for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
+ perms.add(e.nextElement());
+ }
+ }
+ return this;
+ }
+ public Permissions toPermissions() {
+ final PermissionsBuilder builder = new PermissionsBuilder();
+ builder.addAll(perms);
+ return builder.perms;
+ }
+ }
+
+ public static class SimplePolicy extends Policy {
+ public static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+ final static RuntimePermission ACCESS_LOGGER = new RuntimePermission("accessClassInPackage.jdk.internal.logger");
+ final static RuntimePermission ACCESS_LOGGING = new RuntimePermission("accessClassInPackage.sun.util.logging");
+
+ final Permissions permissions;
+ final Permissions allPermissions;
+ final ThreadLocal<AtomicBoolean> allowControl;
+ final ThreadLocal<AtomicBoolean> allowAccess;
+ final ThreadLocal<AtomicBoolean> allowAll;
+ public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl,
+ ThreadLocal<AtomicBoolean> allowAccess,
+ ThreadLocal<AtomicBoolean> allowAll) {
+ this.allowControl = allowControl;
+ this.allowAccess = allowAccess;
+ this.allowAll = allowAll;
+ permissions = new Permissions();
+ allPermissions = new PermissionsBuilder()
+ .add(new java.security.AllPermission())
+ .toPermissions();
+ }
+
+ Permissions getPermissions() {
+ if (allowControl.get().get() || allowAccess.get().get() || allowAll.get().get()) {
+ PermissionsBuilder builder = new PermissionsBuilder()
+ .addAll(permissions);
+ if (allowControl.get().get()) {
+ builder.add(LOGGERFINDER_PERMISSION);
+ }
+ if (allowAccess.get().get()) {
+ builder.add(ACCESS_LOGGER);
+ builder.add(ACCESS_LOGGING);
+ }
+ if (allowAll.get().get()) {
+ builder.addAll(allPermissions);
+ }
+ return builder.toPermissions();
+ }
+ return permissions;
+ }
+
+ @Override
+ public boolean implies(ProtectionDomain domain, Permission permission) {
+ return getPermissions().implies(permission);
+ }
+
+ @Override
+ public PermissionCollection getPermissions(CodeSource codesource) {
+ return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
+ }
+
+ @Override
+ public PermissionCollection getPermissions(ProtectionDomain domain) {
+ return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/jdk/DefaultPlatformLoggerTest/DefaultPlatformLoggerTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,544 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.ResourceBundle;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.logging.Handler;
+import java.util.logging.LogManager;
+import java.util.logging.LogRecord;
+import java.lang.System.LoggerFinder;
+import sun.util.logging.PlatformLogger;
+import sun.util.logging.internal.LoggingProviderImpl;
+
+/**
+ * @test
+ * @bug 8140364
+ * @summary Tests all PlatformLogger methods with the default LoggerFinder JUL backend.
+ * @modules java.base/sun.util.logging java.logging/sun.util.logging.internal
+ * @run main/othervm DefaultPlatformLoggerTest
+ * @author danielfuchs
+ */
+public class DefaultPlatformLoggerTest {
+
+ final static AtomicLong sequencer = new AtomicLong();
+ final static boolean VERBOSE = false;
+ static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+ static final ThreadLocal<AtomicBoolean> allowAll = new ThreadLocal<AtomicBoolean>() {
+ @Override
+ protected AtomicBoolean initialValue() {
+ return new AtomicBoolean(false);
+ }
+ };
+
+ public static final Queue<LogEvent> eventQueue = new ArrayBlockingQueue<>(128);
+
+ public static final class LogEvent implements Cloneable {
+
+ public LogEvent() {
+ this(sequencer.getAndIncrement());
+ }
+
+ LogEvent(long sequenceNumber) {
+ this.sequenceNumber = sequenceNumber;
+ }
+
+ long sequenceNumber;
+ boolean isLoggable;
+ String loggerName;
+ java.util.logging.Level level;
+ ResourceBundle bundle;
+ Throwable thrown;
+ Object[] args;
+ String msg;
+ String className;
+ String methodName;
+
+ Object[] toArray() {
+ return new Object[] {
+ sequenceNumber,
+ isLoggable,
+ loggerName,
+ level,
+ bundle,
+ thrown,
+ args,
+ msg,
+ className,
+ methodName,
+ };
+ }
+
+ @Override
+ public String toString() {
+ return Arrays.deepToString(toArray());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof LogEvent
+ && Objects.deepEquals(this.toArray(), ((LogEvent)obj).toArray());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(toArray());
+ }
+
+ public LogEvent cloneWith(long sequenceNumber)
+ throws CloneNotSupportedException {
+ LogEvent cloned = (LogEvent)super.clone();
+ cloned.sequenceNumber = sequenceNumber;
+ return cloned;
+ }
+
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ java.util.logging.Level level, ResourceBundle bundle,
+ String key, Throwable thrown, Object... params) {
+ return LogEvent.of(sequenceNumber, isLoggable, name,
+ DefaultPlatformLoggerTest.class.getName(),
+ "testLogger", level, bundle, key,
+ thrown, params);
+ }
+ public static LogEvent of(long sequenceNumber,
+ boolean isLoggable, String name,
+ String className, String methodName,
+ java.util.logging.Level level, ResourceBundle bundle,
+ String key, Throwable thrown, Object... params) {
+ LogEvent evt = new LogEvent(sequenceNumber);
+ evt.loggerName = name;
+ evt.level = level;
+ evt.args = params;
+ evt.bundle = bundle;
+ evt.thrown = thrown;
+ evt.msg = key;
+ evt.isLoggable = isLoggable;
+ evt.className = className;
+ evt.methodName = methodName;
+ return evt;
+ }
+
+ }
+
+ static final java.util.logging.Level[] julLevels = {
+ java.util.logging.Level.ALL,
+ new java.util.logging.Level("FINER_THAN_FINEST", java.util.logging.Level.FINEST.intValue() - 10) {},
+ java.util.logging.Level.FINEST,
+ new java.util.logging.Level("FINER_THAN_FINER", java.util.logging.Level.FINER.intValue() - 10) {},
+ java.util.logging.Level.FINER,
+ new java.util.logging.Level("FINER_THAN_FINE", java.util.logging.Level.FINE.intValue() - 10) {},
+ java.util.logging.Level.FINE,
+ new java.util.logging.Level("FINER_THAN_CONFIG", java.util.logging.Level.FINE.intValue() + 10) {},
+ java.util.logging.Level.CONFIG,
+ new java.util.logging.Level("FINER_THAN_INFO", java.util.logging.Level.INFO.intValue() - 10) {},
+ java.util.logging.Level.INFO,
+ new java.util.logging.Level("FINER_THAN_WARNING", java.util.logging.Level.INFO.intValue() + 10) {},
+ java.util.logging.Level.WARNING,
+ new java.util.logging.Level("FINER_THAN_SEVERE", java.util.logging.Level.SEVERE.intValue() - 10) {},
+ java.util.logging.Level.SEVERE,
+ new java.util.logging.Level("FATAL", java.util.logging.Level.SEVERE.intValue() + 10) {},
+ java.util.logging.Level.OFF,
+ };
+
+ static final java.util.logging.Level[] julPlatformLevels = {
+ java.util.logging.Level.FINEST,
+ java.util.logging.Level.FINER,
+ java.util.logging.Level.FINE,
+ java.util.logging.Level.CONFIG,
+ java.util.logging.Level.INFO,
+ java.util.logging.Level.WARNING,
+ java.util.logging.Level.SEVERE,
+ };
+
+
+ public static class MyBundle extends ResourceBundle {
+
+ final ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
+
+ @Override
+ protected Object handleGetObject(String key) {
+ if (key.contains(" (translated)")) {
+ throw new RuntimeException("Unexpected key: " + key);
+ }
+ return map.computeIfAbsent(key, k -> k + " (translated)");
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ return Collections.enumeration(map.keySet());
+ }
+
+ }
+
+ public static class MyHandler extends Handler {
+
+ @Override
+ public java.util.logging.Level getLevel() {
+ return java.util.logging.Level.ALL;
+ }
+
+ @Override
+ public void publish(LogRecord record) {
+ eventQueue.add(LogEvent.of(sequencer.getAndIncrement(),
+ true, record.getLoggerName(),
+ record.getSourceClassName(),
+ record.getSourceMethodName(),
+ record.getLevel(),
+ record.getResourceBundle(), record.getMessage(),
+ record.getThrown(), record.getParameters()));
+ }
+ @Override
+ public void flush() {
+ }
+ @Override
+ public void close() throws SecurityException {
+ }
+
+ }
+
+ public static class MyLoggerBundle extends MyBundle {
+
+ }
+
+ public static void main(String[] args) throws Exception {
+ LoggerFinder provider = LoggerFinder.getLoggerFinder();
+ java.util.logging.Logger appSink = LoggingProviderImpl.getLogManagerAccess()
+ .demandLoggerFor(LogManager.getLogManager(), "foo",
+ DefaultPlatformLoggerTest.class);
+ java.util.logging.Logger sysSink = LoggingProviderImpl.getLogManagerAccess()
+ .demandLoggerFor(LogManager.getLogManager(),"foo", Thread.class);
+ appSink.addHandler(new MyHandler());
+ sysSink.addHandler(new MyHandler());
+ appSink.setUseParentHandlers(VERBOSE);
+ sysSink.setUseParentHandlers(VERBOSE);
+
+ System.out.println("\n*** Without Security Manager\n");
+ test(provider, true, appSink, sysSink);
+ System.out.println("Tetscase count: " + sequencer.get());
+
+ Policy.setPolicy(new SimplePolicy(allowAll, allowControl));
+ System.setSecurityManager(new SecurityManager());
+
+ System.out.println("\n*** With Security Manager, without permissions\n");
+ test(provider, false, appSink, sysSink);
+ System.out.println("Tetscase count: " + sequencer.get());
+
+ System.out.println("\n*** With Security Manager, with control permission\n");
+ allowControl.get().set(true);
+ test(provider, true, appSink, sysSink);
+
+ System.out.println("\nPASSED: Tested " + sequencer.get() + " cases.");
+ }
+
+ public static void test(LoggerFinder provider, boolean hasRequiredPermissions,
+ java.util.logging.Logger appSink, java.util.logging.Logger sysSink) throws Exception {
+
+ // No way to giva a resource bundle to a platform logger.
+ // ResourceBundle loggerBundle = ResourceBundle.getBundle(MyLoggerBundle.class.getName());
+ final Map<PlatformLogger, String> loggerDescMap = new HashMap<>();
+
+ PlatformLogger platform = PlatformLogger.getLogger("foo");
+ loggerDescMap.put(platform, "PlatformLogger.getLogger(\"foo\")");
+
+ testLogger(provider, loggerDescMap, "foo", null, platform, sysSink);
+ }
+
+ public static class Foo {
+
+ }
+
+ static void verbose(String msg) {
+ if (VERBOSE) {
+ System.out.println(msg);
+ }
+ }
+
+ static void checkLogEvent(LoggerFinder provider, String desc,
+ LogEvent expected) {
+ LogEvent actual = eventQueue.poll();
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+
+ static void checkLogEvent(LoggerFinder provider, String desc,
+ LogEvent expected, boolean expectNotNull) {
+ LogEvent actual = eventQueue.poll();
+ if (actual == null && !expectNotNull) return;
+ if (actual != null && !expectNotNull) {
+ throw new RuntimeException("Unexpected log event found for " + desc
+ + "\n\tgot: " + actual);
+ }
+ if (!expected.equals(actual)) {
+ throw new RuntimeException("mismatch for " + desc
+ + "\n\texpected=" + expected
+ + "\n\t actual=" + actual);
+ } else {
+ verbose("Got expected results for "
+ + desc + "\n\t" + expected);
+ }
+ }
+
+ static void setLevel(java.util.logging.Logger sink, java.util.logging.Level loggerLevel) {
+ boolean before = allowAll.get().get();
+ try {
+ allowAll.get().set(true);
+ sink.setLevel(loggerLevel);
+ } finally {
+ allowAll.get().set(before);
+ }
+ }
+
+ // Calls the methods defined on LogProducer and verify the
+ // parameters received by the underlying logger.
+ private static void testLogger(LoggerFinder provider,
+ Map<PlatformLogger, String> loggerDescMap,
+ String name,
+ ResourceBundle loggerBundle,
+ PlatformLogger logger,
+ java.util.logging.Logger sink) throws Exception {
+
+ System.out.println("Testing " + loggerDescMap.get(logger));
+ final java.util.logging.Level OFF = java.util.logging.Level.OFF;
+
+ Foo foo = new Foo();
+ String fooMsg = foo.toString();
+ System.out.println("\tlogger.<level>(fooMsg)");
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (java.util.logging.Level messageLevel : julPlatformLevels) {
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, loggerBundle,
+ fooMsg, (Throwable)null, (Object[])null);
+ String desc2 = "logger." + messageLevel.toString().toLowerCase()
+ + "(fooMsg): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ if (messageLevel == java.util.logging.Level.FINEST) {
+ logger.finest(fooMsg);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ } else if (messageLevel == java.util.logging.Level.FINER) {
+ logger.finer(fooMsg);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ } else if (messageLevel == java.util.logging.Level.FINE) {
+ logger.fine(fooMsg);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ } else if (messageLevel == java.util.logging.Level.CONFIG) {
+ logger.config(fooMsg);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ } else if (messageLevel == java.util.logging.Level.INFO) {
+ logger.info(fooMsg);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ } else if (messageLevel == java.util.logging.Level.WARNING) {
+ logger.warning(fooMsg);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ } else if (messageLevel == java.util.logging.Level.SEVERE) {
+ logger.severe(fooMsg);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ }
+ }
+ }
+
+ Throwable thrown = new Exception("OK: log me!");
+ System.out.println("\tlogger.<level>(msg, thrown)");
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (java.util.logging.Level messageLevel :julPlatformLevels) {
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, loggerBundle,
+ fooMsg, thrown, (Object[])null);
+ String desc2 = "logger." + messageLevel.toString().toLowerCase()
+ + "(msg, thrown): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ if (messageLevel == java.util.logging.Level.FINEST) {
+ logger.finest(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ } else if (messageLevel == java.util.logging.Level.FINER) {
+ logger.finer(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ } else if (messageLevel == java.util.logging.Level.FINE) {
+ logger.fine(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ } else if (messageLevel == java.util.logging.Level.CONFIG) {
+ logger.config(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ } else if (messageLevel == java.util.logging.Level.INFO) {
+ logger.info(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ } else if (messageLevel == java.util.logging.Level.WARNING) {
+ logger.warning(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ } else if (messageLevel == java.util.logging.Level.SEVERE) {
+ logger.severe(fooMsg, thrown);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ }
+ }
+ }
+
+ String format = "two params [{1} {2}]";
+ Object arg1 = foo;
+ Object arg2 = fooMsg;
+ System.out.println("\tlogger.<level>(format, arg1, arg2)");
+ for (java.util.logging.Level loggerLevel : julLevels) {
+ setLevel(sink, loggerLevel);
+ for (java.util.logging.Level messageLevel : julPlatformLevels) {
+ LogEvent expected =
+ LogEvent.of(
+ sequencer.get(),
+ loggerLevel != OFF && messageLevel.intValue() >= loggerLevel.intValue(),
+ name, messageLevel, loggerBundle,
+ format, (Throwable)null, foo, fooMsg);
+ String desc2 = "logger." + messageLevel.toString().toLowerCase()
+ + "(format, foo, fooMsg): loggerLevel="
+ + loggerLevel+", messageLevel="+messageLevel;
+ if (messageLevel == java.util.logging.Level.FINEST) {
+ logger.finest(format, foo, fooMsg);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ } else if (messageLevel == java.util.logging.Level.FINER) {
+ logger.finer(format, foo, fooMsg);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ } else if (messageLevel == java.util.logging.Level.FINE) {
+ logger.fine(format, foo, fooMsg);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ } else if (messageLevel == java.util.logging.Level.CONFIG) {
+ logger.config(format, foo, fooMsg);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ } else if (messageLevel == java.util.logging.Level.INFO) {
+ logger.info(format, foo, fooMsg);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ } else if (messageLevel == java.util.logging.Level.WARNING) {
+ logger.warning(format, foo, fooMsg);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ } else if (messageLevel == java.util.logging.Level.SEVERE) {
+ logger.severe(format, foo, fooMsg);
+ checkLogEvent(provider, desc2, expected, expected.isLoggable);
+ }
+ }
+ }
+
+ }
+
+ final static class PermissionsBuilder {
+ final Permissions perms;
+ public PermissionsBuilder() {
+ this(new Permissions());
+ }
+ public PermissionsBuilder(Permissions perms) {
+ this.perms = perms;
+ }
+ public PermissionsBuilder add(Permission p) {
+ perms.add(p);
+ return this;
+ }
+ public PermissionsBuilder addAll(PermissionCollection col) {
+ if (col != null) {
+ for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
+ perms.add(e.nextElement());
+ }
+ }
+ return this;
+ }
+ public Permissions toPermissions() {
+ final PermissionsBuilder builder = new PermissionsBuilder();
+ builder.addAll(perms);
+ return builder.perms;
+ }
+ }
+
+ public static class SimplePolicy extends Policy {
+ public static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+
+ final Permissions permissions;
+ final Permissions withControlPermissions;
+ final Permissions allPermissions;
+ final ThreadLocal<AtomicBoolean> allowAll;
+ final ThreadLocal<AtomicBoolean> allowControl;
+ public SimplePolicy(ThreadLocal<AtomicBoolean> allowAll,
+ ThreadLocal<AtomicBoolean> allowControl) {
+ this.allowAll = allowAll;
+ this.allowControl = allowControl;
+ permissions = new Permissions();
+
+ withControlPermissions = new Permissions();
+ withControlPermissions.add(LOGGERFINDER_PERMISSION);
+
+ // these are used for configuring the test itself...
+ allPermissions = new Permissions();
+ allPermissions.add(new java.security.AllPermission());
+ }
+
+ @Override
+ public boolean implies(ProtectionDomain domain, Permission permission) {
+ if (allowAll.get().get()) return allPermissions.implies(permission);
+ if (allowControl.get().get()) return withControlPermissions.implies(permission);
+ return permissions.implies(permission);
+ }
+
+ @Override
+ public PermissionCollection getPermissions(CodeSource codesource) {
+ return new PermissionsBuilder().addAll(
+ allowAll.get().get() ? allPermissions :
+ allowControl.get().get()
+ ? withControlPermissions : permissions).toPermissions();
+ }
+
+ @Override
+ public PermissionCollection getPermissions(ProtectionDomain domain) {
+ return new PermissionsBuilder().addAll(
+ allowAll.get().get() ? allPermissions :
+ allowControl.get().get()
+ ? withControlPermissions : permissions).toPermissions();
+ }
+ }
+}
--- a/jdk/test/java/lang/invoke/AccessControlTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/lang/invoke/AccessControlTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -225,6 +225,31 @@
System.out.println(this+" willAccess "+lc+" m1="+m1+" m2="+m2+" => "+((m2 & m1) != 0));
return (m2 & m1) != 0;
}
+
+ /** Predict the success or failure of accessing this class. */
+ public boolean willAccessClass(Class<?> c2, boolean load) {
+ Class<?> c1 = lookupClass();
+ if (load && c1.getClassLoader() == null) {
+ return false;
+ }
+ LookupCase lc = this.in(c2);
+ int m1 = lc.lookupModes();
+ boolean r = false;
+ if (m1 == 0) {
+ r = false;
+ } else {
+ int m2 = fixMods(c2.getModifiers());
+ if ((m2 & PUBLIC) != 0) {
+ r = true;
+ } else if ((m1 & PACKAGE) != 0 && c1.getPackage() == c2.getPackage()) {
+ r = true;
+ }
+ }
+ if (verbosity >= 2) {
+ System.out.println(this+" willAccessClass "+lc+" c1="+c1+" c2="+c2+" => "+r);
+ }
+ return r;
+ }
}
private static Class<?> topLevelClass(Class<?> cls) {
@@ -342,6 +367,8 @@
Method method = targetMethod(targetClass, targetAccess, methodType);
// Try to access target method from various contexts.
for (LookupCase sourceCase : CASES) {
+ testOneAccess(sourceCase, method, "findClass");
+ testOneAccess(sourceCase, method, "accessClass");
testOneAccess(sourceCase, method, "find");
testOneAccess(sourceCase, method, "unreflect");
}
@@ -356,11 +383,19 @@
Class<?> targetClass = method.getDeclaringClass();
String methodName = method.getName();
MethodType methodType = methodType(method.getReturnType(), method.getParameterTypes());
- boolean willAccess = sourceCase.willAccess(method);
+ boolean isFindOrAccessClass = "findClass".equals(kind) || "accessClass".equals(kind);
+ boolean willAccess = isFindOrAccessClass ?
+ sourceCase.willAccessClass(targetClass, "findClass".equals(kind)) : sourceCase.willAccess(method);
boolean didAccess = false;
ReflectiveOperationException accessError = null;
try {
switch (kind) {
+ case "accessClass":
+ sourceCase.lookup().accessClass(targetClass);
+ break;
+ case "findClass":
+ sourceCase.lookup().findClass(targetClass.getName());
+ break;
case "find":
if ((method.getModifiers() & Modifier.STATIC) != 0)
sourceCase.lookup().findStatic(targetClass, methodName, methodType);
@@ -378,8 +413,8 @@
accessError = ex;
}
if (willAccess != didAccess) {
- System.out.println(sourceCase+" => "+targetClass.getSimpleName()+"."+methodName+methodType);
- System.out.println("fail on "+method+" ex="+accessError);
+ System.out.println(sourceCase+" => "+targetClass.getSimpleName()+(isFindOrAccessClass?"":"."+methodName+methodType));
+ System.out.println("fail "+(isFindOrAccessClass?kind:"on "+method)+" ex="+accessError);
assertEquals(willAccess, didAccess);
}
testCount++;
--- a/jdk/test/java/lang/invoke/BigArityTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/lang/invoke/BigArityTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -58,6 +58,8 @@
return x == null ? dflt : x;
}
+ static final MethodType MT_A = MethodType.methodType(Object.class, Object.class, Object[].class, Object.class);
+
static Object hashArguments(Object... args) {
return Objects.hash(args);
}
@@ -108,9 +110,36 @@
}
}
// Sizes not in the above array are good:
- target.asCollector(Object[].class, minbig-1);
+ target.asCollector(Object[].class, minbig - 1);
for (int i = 2; i <= 10; i++)
- target.asCollector(Object[].class, minbig-i);
+ target.asCollector(Object[].class, minbig - i);
+ }
+
+ static void asciae02target(Object[] a, Object b) {
+ // naught
+ }
+
+ @Test
+ public void asCollectorIAE02() throws ReflectiveOperationException {
+ final int[] INVALID_ARRAY_LENGTHS = {
+ Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -2, -1, 254, 255, Integer.MAX_VALUE - 1, Integer.MAX_VALUE
+ };
+ MethodHandle target = MethodHandles.lookup().findStatic(BigArityTest.class, "asciae02target",
+ MethodType.methodType(void.class, Object[].class, Object.class));
+ int minbig = Integer.MAX_VALUE;
+ for (int invalidLength : INVALID_ARRAY_LENGTHS) {
+ if (minbig > invalidLength && invalidLength > 100) minbig = invalidLength;
+ try {
+ target.asCollector(0, Object[].class, invalidLength);
+ assert(false) : invalidLength;
+ } catch (IllegalArgumentException ex) {
+ System.out.println("OK: "+ex);
+ }
+ }
+ // Sizes not in the above array are good:
+ for (int i = 1; i <= 10; ++i) {
+ target.asCollector(0, Object[].class, minbig - i);
+ }
}
@Test
@@ -216,51 +245,86 @@
Class<? extends Object[]> cls = (Class<? extends Object[]>) cls0;
//Class<? extends Object[]> cls = Object[].class.asSubclass(cls0);
int nargs = args.length, skip;
+ Object hr;
MethodHandle smh = mh.asSpreader(cls, nargs - (skip = 0));
+ MethodHandle hsmh = mh.asSpreader(0, cls, nargs - skip);
Object[] tail = Arrays.copyOfRange(args, skip, nargs, cls);
- if (cls == Object[].class)
+ Object[] head = Arrays.copyOfRange(args, 0, nargs - skip, cls);
+ if (cls == Object[].class) {
r = smh.invokeExact(tail);
- else if (cls == Integer[].class)
+ hr = hsmh.invokeExact(head);
+ } else if (cls == Integer[].class) {
r = smh.invokeExact((Integer[]) tail); //warning OK, see 8019340
- else
+ hr = hsmh.invokeExact((Integer[]) head);
+ } else {
r = smh.invoke(tail);
+ hr = hsmh.invoke(head);
+ }
assertEquals(r0, r);
+ assertEquals(r0, hr);
smh = mh.asSpreader(cls, nargs - (skip = 1));
+ hsmh = mh.asSpreader(0, cls, nargs - skip);
tail = Arrays.copyOfRange(args, skip, nargs, cls);
- if (cls == Object[].class)
+ head = Arrays.copyOfRange(args, 0, nargs - skip, cls);
+ if (cls == Object[].class) {
r = smh.invokeExact(args[0], tail);
- else if (cls == Integer[].class)
+ hr = hsmh.invokeExact(head, args[2]);
+ } else if (cls == Integer[].class) {
r = smh.invokeExact(args[0], (Integer[]) tail);
- else
+ hr = hsmh.invokeExact((Integer[]) head, args[2]);
+ } else {
r = smh.invoke(args[0], tail);
+ hr = hsmh.invoke(head, args[2]);
+ }
assertEquals(r0, r);
+ assertEquals(r0, hr);
smh = mh.asSpreader(cls, nargs - (skip = 2));
+ hsmh = mh.asSpreader(0, cls, nargs - skip);
tail = Arrays.copyOfRange(args, skip, nargs, cls);
- if (cls == Object[].class)
+ head = Arrays.copyOfRange(args, 0, nargs - skip, cls);
+ if (cls == Object[].class) {
r = smh.invokeExact(args[0], args[1], tail);
- else if (cls == Integer[].class)
+ hr = hsmh.invokeExact(head, args[1], args[2]);
+ } else if (cls == Integer[].class) {
r = smh.invokeExact(args[0], args[1], (Integer[]) tail);
- else
+ hr = hsmh.invokeExact((Integer[]) head, args[1], args[2]);
+ } else {
r = smh.invoke(args[0], args[1], tail);
+ hr = hsmh.invoke(head, args[1], args[2]);
+ }
assertEquals(r0, r);
+ assertEquals(r0, hr);
smh = mh.asSpreader(cls, nargs - (skip = 3));
+ hsmh = mh.asSpreader(0, cls, nargs - skip);
tail = Arrays.copyOfRange(args, skip, nargs, cls);
- if (cls == Object[].class)
+ head = Arrays.copyOfRange(args, 0, nargs - skip, cls);
+ if (cls == Object[].class) {
r = smh.invokeExact(args[0], args[1], args[2], tail);
- else if (cls == Integer[].class)
+ hr = hsmh.invokeExact(head, args[0], args[1], args[2]);
+ } else if (cls == Integer[].class) {
r = smh.invokeExact(args[0], args[1], args[2], (Integer[]) tail);
- else
+ hr = hsmh.invokeExact((Integer[]) head, args[0], args[1], args[2]);
+ } else {
r = smh.invoke(args[0], args[1], args[2], tail);
+ hr = hsmh.invoke(head, args[0], args[1], args[2]);
+ }
assertEquals(r0, r);
+ assertEquals(r0, hr);
// Try null array in addition to zero-length array:
tail = null;
- if (cls == Object[].class)
+ head = null;
+ if (cls == Object[].class) {
r = smh.invokeExact(args[0], args[1], args[2], tail);
- else if (cls == Integer[].class)
+ hr = hsmh.invokeExact(head, args[0], args[1], args[2]);
+ } else if (cls == Integer[].class) {
r = smh.invokeExact(args[0], args[1], args[2], (Integer[]) tail);
- else
+ hr = hsmh.invokeExact((Integer[]) head, args[0], args[1], args[2]);
+ } else {
r = smh.invoke(args[0], args[1], args[2], tail);
+ hr = hsmh.invoke(head, args[0], args[1], args[2]);
+ }
assertEquals(r0, r);
+ assertEquals(r0, hr);
}
}
@@ -292,7 +356,7 @@
@Test
public void testArities() throws Throwable {
System.out.println("testing spreaders and collectors on high arities...");
- int iterations = ITERATION_COUNT;
+ int iterations = ITERATION_COUNT;
testArities(Object[].class, MIN_ARITY-10, MIN_ARITY-1, iterations / 1000);
testArities(Object[].class, MIN_ARITY, SLOW_ARITY-1, iterations);
testArities(Object[].class, SLOW_ARITY, MAX_ARITY, iterations / 1000);
@@ -307,8 +371,13 @@
Class<? extends Object[]> cls = (Class<? extends Object[]>) cls0;
System.out.println("array class: "+cls.getSimpleName());
int iterations = ITERATION_COUNT / 1000;
- testArities(cls, MIN_ARITY, SLOW_ARITY-1, iterations);
- testArities(cls, SLOW_ARITY, MAX_ARITY, iterations / 100);
+ try {
+ testArities(cls, MIN_ARITY, SLOW_ARITY - 1, iterations);
+ testArities(cls, SLOW_ARITY, MAX_ARITY, iterations / 100);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ throw t;
+ }
}
}
@@ -321,11 +390,14 @@
if (verbose) System.out.println("arity="+arity);
MethodHandle mh = MH_hashArguments(cls, arity);
MethodHandle mh_VA = mh.asSpreader(cls, arity);
+ MethodHandle mh_VA_h = mh.asSpreader(0, cls, arity-1);
assert(mh_VA.type().parameterType(0) == cls);
- testArities(cls, arity, iterations, verbose, mh, mh_VA);
+ assert(mh_VA_h.type().parameterType(0) == cls);
+ testArities(cls, arity, iterations, verbose, mh, mh_VA, mh_VA_h);
// mh_CA will collect arguments of a particular type and pass them to mh_VA
MethodHandle mh_CA = mh_VA.asCollector(cls, arity);
MethodHandle mh_VA2 = mh_CA.asSpreader(cls, arity);
+ MethodHandle mh_VA2_h = mh_CA.asSpreader(0, cls, arity-1);
assert(mh_CA.type().equals(mh.type()));
assert(mh_VA2.type().equals(mh_VA.type()));
if (cls != Object[].class) {
@@ -336,7 +408,7 @@
}
}
int iterations_VA = iterations / 100;
- testArities(cls, arity, iterations_VA, false, mh_CA, mh_VA2);
+ testArities(cls, arity, iterations_VA, false, mh_CA, mh_VA2, mh_VA2_h);
}
}
@@ -357,13 +429,16 @@
* @param verbose are we printing extra output?
* @param mh a fixed-arity version of {@code hashArguments}
* @param mh_VA a variable-arity version of {@code hashArguments}, accepting the given array type {@code cls}
+ * @param mh_VA_h a version of {@code hashArguments} that has a leading {@code cls} array and one final {@code cls}
+ * argument
*/
private void testArities(Class<? extends Object[]> cls,
int arity,
int iterations,
boolean verbose,
MethodHandle mh,
- MethodHandle mh_VA
+ MethodHandle mh_VA,
+ MethodHandle mh_VA_h
) throws Throwable {
if (iterations < 4) iterations = 4;
final int MAX_MH_ARITY = MAX_JVM_ARITY - 1; // mh.invoke(arg*[N])
@@ -373,6 +448,7 @@
args = Arrays.copyOf(args, arity, cls);
Object r0 = Objects.hash(args);
Object r;
+ Object hr;
MethodHandle ximh = null;
MethodHandle gimh = null;
if (arity <= MAX_INVOKER_ARITY) {
@@ -397,13 +473,18 @@
Object[] mh_args = cat(mh, args);
assert(arity <= MAX_MH_ARITY);
for (int i = 0; i < iterations; ++i) {
- if (cls == Object[].class)
+ if (cls == Object[].class) {
r = mh_VA.invokeExact(args);
- else if (cls == Integer[].class)
- r = mh_VA.invokeExact((Integer[])args); //warning OK, see 8019340
- else
+ hr = mh_VA_h.invokeExact(Arrays.copyOfRange(args, 0, arity - 1), args[arity - 1]);
+ } else if (cls == Integer[].class) {
+ r = mh_VA.invokeExact((Integer[]) args); //warning OK, see 8019340
+ hr = mh_VA_h.invokeExact((Integer[]) Arrays.copyOfRange(args, 0, arity - 1), (Integer) args[arity - 1]);
+ } else {
r = mh_VA.invoke(args);
+ hr = mh_VA_h.invoke(Arrays.copyOfRange(args, 0, arity - 1), args[arity - 1]);
+ }
assertEquals(r0, r);
+ assertEquals(r0, hr);
r = mh.invokeWithArguments(args);
assertEquals(r0, r);
if (ximh != null) {
@@ -473,6 +554,43 @@
// </editor-fold>
xF8, xF9, xFA, xFB);
}
+ static Object hashArguments_252_a(Object x00, Object[] x01_FA, Object xFB) {
+ return Objects.hash(
+ // <editor-fold defaultstate="collapsed" desc="x00, x01_FA[0], x01_FA[1], x01_FA[2], ...">
+ x00, x01_FA[0], x01_FA[1], x01_FA[2], x01_FA[3], x01_FA[4], x01_FA[5], x01_FA[6], x01_FA[7], x01_FA[8],
+ x01_FA[9], x01_FA[10], x01_FA[11], x01_FA[12], x01_FA[13], x01_FA[14], x01_FA[15], x01_FA[16],
+ x01_FA[17], x01_FA[18], x01_FA[19], x01_FA[20], x01_FA[21], x01_FA[22], x01_FA[23], x01_FA[24],
+ x01_FA[25], x01_FA[26], x01_FA[27], x01_FA[28], x01_FA[29], x01_FA[30], x01_FA[31], x01_FA[32],
+ x01_FA[33], x01_FA[34], x01_FA[35], x01_FA[36], x01_FA[37], x01_FA[38], x01_FA[39], x01_FA[40],
+ x01_FA[41], x01_FA[42], x01_FA[43], x01_FA[44], x01_FA[45], x01_FA[46], x01_FA[47], x01_FA[48],
+ x01_FA[49], x01_FA[50], x01_FA[51], x01_FA[52], x01_FA[53], x01_FA[54], x01_FA[55], x01_FA[56],
+ x01_FA[57], x01_FA[58], x01_FA[59], x01_FA[60], x01_FA[61], x01_FA[62], x01_FA[63], x01_FA[64],
+ x01_FA[65], x01_FA[66], x01_FA[67], x01_FA[68], x01_FA[69], x01_FA[70], x01_FA[71], x01_FA[72],
+ x01_FA[73], x01_FA[74], x01_FA[75], x01_FA[76], x01_FA[77], x01_FA[78], x01_FA[79], x01_FA[80],
+ x01_FA[81], x01_FA[82], x01_FA[83], x01_FA[84], x01_FA[85], x01_FA[86], x01_FA[87], x01_FA[88],
+ x01_FA[89], x01_FA[90], x01_FA[91], x01_FA[92], x01_FA[93], x01_FA[94], x01_FA[95], x01_FA[96],
+ x01_FA[97], x01_FA[98], x01_FA[99], x01_FA[100], x01_FA[101], x01_FA[102], x01_FA[103], x01_FA[104],
+ x01_FA[105], x01_FA[106], x01_FA[107], x01_FA[108], x01_FA[109], x01_FA[110], x01_FA[111], x01_FA[112],
+ x01_FA[113], x01_FA[114], x01_FA[115], x01_FA[116], x01_FA[117], x01_FA[118], x01_FA[119], x01_FA[120],
+ x01_FA[121], x01_FA[122], x01_FA[123], x01_FA[124], x01_FA[125], x01_FA[126], x01_FA[127], x01_FA[128],
+ x01_FA[129], x01_FA[130], x01_FA[131], x01_FA[132], x01_FA[133], x01_FA[134], x01_FA[135], x01_FA[136],
+ x01_FA[137], x01_FA[138], x01_FA[139], x01_FA[140], x01_FA[141], x01_FA[142], x01_FA[143], x01_FA[144],
+ x01_FA[145], x01_FA[146], x01_FA[147], x01_FA[148], x01_FA[149], x01_FA[150], x01_FA[151], x01_FA[152],
+ x01_FA[153], x01_FA[154], x01_FA[155], x01_FA[156], x01_FA[157], x01_FA[158], x01_FA[159], x01_FA[160],
+ x01_FA[161], x01_FA[162], x01_FA[163], x01_FA[164], x01_FA[165], x01_FA[166], x01_FA[167], x01_FA[168],
+ x01_FA[169], x01_FA[170], x01_FA[171], x01_FA[172], x01_FA[173], x01_FA[174], x01_FA[175], x01_FA[176],
+ x01_FA[177], x01_FA[178], x01_FA[179], x01_FA[180], x01_FA[181], x01_FA[182], x01_FA[183], x01_FA[184],
+ x01_FA[185], x01_FA[186], x01_FA[187], x01_FA[188], x01_FA[189], x01_FA[190], x01_FA[191], x01_FA[192],
+ x01_FA[193], x01_FA[194], x01_FA[195], x01_FA[196], x01_FA[197], x01_FA[198], x01_FA[199], x01_FA[200],
+ x01_FA[201], x01_FA[202], x01_FA[203], x01_FA[204], x01_FA[205], x01_FA[206], x01_FA[207], x01_FA[208],
+ x01_FA[209], x01_FA[210], x01_FA[211], x01_FA[212], x01_FA[213], x01_FA[214], x01_FA[215], x01_FA[216],
+ x01_FA[217], x01_FA[218], x01_FA[219], x01_FA[220], x01_FA[221], x01_FA[222], x01_FA[223], x01_FA[224],
+ x01_FA[225], x01_FA[226], x01_FA[227], x01_FA[228], x01_FA[229], x01_FA[230], x01_FA[231], x01_FA[232],
+ x01_FA[233], x01_FA[234], x01_FA[235], x01_FA[236], x01_FA[237], x01_FA[238], x01_FA[239], x01_FA[240],
+ x01_FA[241], x01_FA[242], x01_FA[243], x01_FA[244], x01_FA[245], x01_FA[246], x01_FA[247], x01_FA[248],
+ // </editor-fold>
+ x01_FA[249], xFB);
+ }
@Test
public void test252() throws Throwable {
@@ -507,6 +625,8 @@
test252(mh, a, r0);
MethodHandle mh_CA = MH_hashArguments_VA.asFixedArity().asCollector(Object[].class, ARITY);
test252(mh_CA, a, r0);
+ MethodHandle mh_a = MethodHandles.lookup().findStatic(BigArityTest.class, "hashArguments_"+ARITY+"_a", MT_A).asCollector(1, Object[].class, ARITY-2);
+ test252(mh_a, a, r0);
}
public void test252(MethodHandle mh, Object[] a, Object r0) throws Throwable {
Object r;
@@ -686,6 +806,43 @@
// </editor-fold>
xF8, xF9, xFA, xFB, xFC);
}
+ static Object hashArguments_253_a(Object x00, Object[] x01_FB, Object xFC) {
+ return Objects.hash(
+ // <editor-fold defaultstate="collapsed" desc="x00, x01_FB[0], x01_FB[1], x01_FB[2], ...">
+ x00, x01_FB[0], x01_FB[1], x01_FB[2], x01_FB[3], x01_FB[4], x01_FB[5], x01_FB[6], x01_FB[7], x01_FB[8],
+ x01_FB[9], x01_FB[10], x01_FB[11], x01_FB[12], x01_FB[13], x01_FB[14], x01_FB[15], x01_FB[16],
+ x01_FB[17], x01_FB[18], x01_FB[19], x01_FB[20], x01_FB[21], x01_FB[22], x01_FB[23], x01_FB[24],
+ x01_FB[25], x01_FB[26], x01_FB[27], x01_FB[28], x01_FB[29], x01_FB[30], x01_FB[31], x01_FB[32],
+ x01_FB[33], x01_FB[34], x01_FB[35], x01_FB[36], x01_FB[37], x01_FB[38], x01_FB[39], x01_FB[40],
+ x01_FB[41], x01_FB[42], x01_FB[43], x01_FB[44], x01_FB[45], x01_FB[46], x01_FB[47], x01_FB[48],
+ x01_FB[49], x01_FB[50], x01_FB[51], x01_FB[52], x01_FB[53], x01_FB[54], x01_FB[55], x01_FB[56],
+ x01_FB[57], x01_FB[58], x01_FB[59], x01_FB[60], x01_FB[61], x01_FB[62], x01_FB[63], x01_FB[64],
+ x01_FB[65], x01_FB[66], x01_FB[67], x01_FB[68], x01_FB[69], x01_FB[70], x01_FB[71], x01_FB[72],
+ x01_FB[73], x01_FB[74], x01_FB[75], x01_FB[76], x01_FB[77], x01_FB[78], x01_FB[79], x01_FB[80],
+ x01_FB[81], x01_FB[82], x01_FB[83], x01_FB[84], x01_FB[85], x01_FB[86], x01_FB[87], x01_FB[88],
+ x01_FB[89], x01_FB[90], x01_FB[91], x01_FB[92], x01_FB[93], x01_FB[94], x01_FB[95], x01_FB[96],
+ x01_FB[97], x01_FB[98], x01_FB[99], x01_FB[100], x01_FB[101], x01_FB[102], x01_FB[103], x01_FB[104],
+ x01_FB[105], x01_FB[106], x01_FB[107], x01_FB[108], x01_FB[109], x01_FB[110], x01_FB[111], x01_FB[112],
+ x01_FB[113], x01_FB[114], x01_FB[115], x01_FB[116], x01_FB[117], x01_FB[118], x01_FB[119], x01_FB[120],
+ x01_FB[121], x01_FB[122], x01_FB[123], x01_FB[124], x01_FB[125], x01_FB[126], x01_FB[127], x01_FB[128],
+ x01_FB[129], x01_FB[130], x01_FB[131], x01_FB[132], x01_FB[133], x01_FB[134], x01_FB[135], x01_FB[136],
+ x01_FB[137], x01_FB[138], x01_FB[139], x01_FB[140], x01_FB[141], x01_FB[142], x01_FB[143], x01_FB[144],
+ x01_FB[145], x01_FB[146], x01_FB[147], x01_FB[148], x01_FB[149], x01_FB[150], x01_FB[151], x01_FB[152],
+ x01_FB[153], x01_FB[154], x01_FB[155], x01_FB[156], x01_FB[157], x01_FB[158], x01_FB[159], x01_FB[160],
+ x01_FB[161], x01_FB[162], x01_FB[163], x01_FB[164], x01_FB[165], x01_FB[166], x01_FB[167], x01_FB[168],
+ x01_FB[169], x01_FB[170], x01_FB[171], x01_FB[172], x01_FB[173], x01_FB[174], x01_FB[175], x01_FB[176],
+ x01_FB[177], x01_FB[178], x01_FB[179], x01_FB[180], x01_FB[181], x01_FB[182], x01_FB[183], x01_FB[184],
+ x01_FB[185], x01_FB[186], x01_FB[187], x01_FB[188], x01_FB[189], x01_FB[190], x01_FB[191], x01_FB[192],
+ x01_FB[193], x01_FB[194], x01_FB[195], x01_FB[196], x01_FB[197], x01_FB[198], x01_FB[199], x01_FB[200],
+ x01_FB[201], x01_FB[202], x01_FB[203], x01_FB[204], x01_FB[205], x01_FB[206], x01_FB[207], x01_FB[208],
+ x01_FB[209], x01_FB[210], x01_FB[211], x01_FB[212], x01_FB[213], x01_FB[214], x01_FB[215], x01_FB[216],
+ x01_FB[217], x01_FB[218], x01_FB[219], x01_FB[220], x01_FB[221], x01_FB[222], x01_FB[223], x01_FB[224],
+ x01_FB[225], x01_FB[226], x01_FB[227], x01_FB[228], x01_FB[229], x01_FB[230], x01_FB[231], x01_FB[232],
+ x01_FB[233], x01_FB[234], x01_FB[235], x01_FB[236], x01_FB[237], x01_FB[238], x01_FB[239], x01_FB[240],
+ x01_FB[241], x01_FB[242], x01_FB[243], x01_FB[244], x01_FB[245], x01_FB[246], x01_FB[247], x01_FB[248],
+ // </editor-fold>
+ x01_FB[249], x01_FB[250], xFC);
+ }
@Test
public void test253() throws Throwable {
@@ -720,6 +877,8 @@
test253(mh, a, r0);
MethodHandle mh_CA = MH_hashArguments_VA.asFixedArity().asCollector(Object[].class, ARITY);
test253(mh_CA, a, r0);
+ MethodHandle mh_a = MethodHandles.lookup().findStatic(BigArityTest.class, "hashArguments_"+ARITY+"_a", MT_A).asCollector(1, Object[].class, ARITY-2);
+ test253(mh_a, a, r0);
}
public void test253(MethodHandle mh, Object[] a, Object r0) throws Throwable {
Object r;
@@ -899,6 +1058,43 @@
// </editor-fold>
xF8, xF9, xFA, xFB, xFC, xFD);
}
+ static Object hashArguments_254_a(Object x00, Object[] x01_FC, Object xFD) {
+ return Objects.hash(
+ // <editor-fold defaultstate="collapsed" desc="x00, x01_FC[0], x01_FC[1], x01_FC[2], ...">
+ x00, x01_FC[0], x01_FC[1], x01_FC[2], x01_FC[3], x01_FC[4], x01_FC[5], x01_FC[6], x01_FC[7], x01_FC[8],
+ x01_FC[9], x01_FC[10], x01_FC[11], x01_FC[12], x01_FC[13], x01_FC[14], x01_FC[15], x01_FC[16],
+ x01_FC[17], x01_FC[18], x01_FC[19], x01_FC[20], x01_FC[21], x01_FC[22], x01_FC[23], x01_FC[24],
+ x01_FC[25], x01_FC[26], x01_FC[27], x01_FC[28], x01_FC[29], x01_FC[30], x01_FC[31], x01_FC[32],
+ x01_FC[33], x01_FC[34], x01_FC[35], x01_FC[36], x01_FC[37], x01_FC[38], x01_FC[39], x01_FC[40],
+ x01_FC[41], x01_FC[42], x01_FC[43], x01_FC[44], x01_FC[45], x01_FC[46], x01_FC[47], x01_FC[48],
+ x01_FC[49], x01_FC[50], x01_FC[51], x01_FC[52], x01_FC[53], x01_FC[54], x01_FC[55], x01_FC[56],
+ x01_FC[57], x01_FC[58], x01_FC[59], x01_FC[60], x01_FC[61], x01_FC[62], x01_FC[63], x01_FC[64],
+ x01_FC[65], x01_FC[66], x01_FC[67], x01_FC[68], x01_FC[69], x01_FC[70], x01_FC[71], x01_FC[72],
+ x01_FC[73], x01_FC[74], x01_FC[75], x01_FC[76], x01_FC[77], x01_FC[78], x01_FC[79], x01_FC[80],
+ x01_FC[81], x01_FC[82], x01_FC[83], x01_FC[84], x01_FC[85], x01_FC[86], x01_FC[87], x01_FC[88],
+ x01_FC[89], x01_FC[90], x01_FC[91], x01_FC[92], x01_FC[93], x01_FC[94], x01_FC[95], x01_FC[96],
+ x01_FC[97], x01_FC[98], x01_FC[99], x01_FC[100], x01_FC[101], x01_FC[102], x01_FC[103], x01_FC[104],
+ x01_FC[105], x01_FC[106], x01_FC[107], x01_FC[108], x01_FC[109], x01_FC[110], x01_FC[111], x01_FC[112],
+ x01_FC[113], x01_FC[114], x01_FC[115], x01_FC[116], x01_FC[117], x01_FC[118], x01_FC[119], x01_FC[120],
+ x01_FC[121], x01_FC[122], x01_FC[123], x01_FC[124], x01_FC[125], x01_FC[126], x01_FC[127], x01_FC[128],
+ x01_FC[129], x01_FC[130], x01_FC[131], x01_FC[132], x01_FC[133], x01_FC[134], x01_FC[135], x01_FC[136],
+ x01_FC[137], x01_FC[138], x01_FC[139], x01_FC[140], x01_FC[141], x01_FC[142], x01_FC[143], x01_FC[144],
+ x01_FC[145], x01_FC[146], x01_FC[147], x01_FC[148], x01_FC[149], x01_FC[150], x01_FC[151], x01_FC[152],
+ x01_FC[153], x01_FC[154], x01_FC[155], x01_FC[156], x01_FC[157], x01_FC[158], x01_FC[159], x01_FC[160],
+ x01_FC[161], x01_FC[162], x01_FC[163], x01_FC[164], x01_FC[165], x01_FC[166], x01_FC[167], x01_FC[168],
+ x01_FC[169], x01_FC[170], x01_FC[171], x01_FC[172], x01_FC[173], x01_FC[174], x01_FC[175], x01_FC[176],
+ x01_FC[177], x01_FC[178], x01_FC[179], x01_FC[180], x01_FC[181], x01_FC[182], x01_FC[183], x01_FC[184],
+ x01_FC[185], x01_FC[186], x01_FC[187], x01_FC[188], x01_FC[189], x01_FC[190], x01_FC[191], x01_FC[192],
+ x01_FC[193], x01_FC[194], x01_FC[195], x01_FC[196], x01_FC[197], x01_FC[198], x01_FC[199], x01_FC[200],
+ x01_FC[201], x01_FC[202], x01_FC[203], x01_FC[204], x01_FC[205], x01_FC[206], x01_FC[207], x01_FC[208],
+ x01_FC[209], x01_FC[210], x01_FC[211], x01_FC[212], x01_FC[213], x01_FC[214], x01_FC[215], x01_FC[216],
+ x01_FC[217], x01_FC[218], x01_FC[219], x01_FC[220], x01_FC[221], x01_FC[222], x01_FC[223], x01_FC[224],
+ x01_FC[225], x01_FC[226], x01_FC[227], x01_FC[228], x01_FC[229], x01_FC[230], x01_FC[231], x01_FC[232],
+ x01_FC[233], x01_FC[234], x01_FC[235], x01_FC[236], x01_FC[237], x01_FC[238], x01_FC[239], x01_FC[240],
+ x01_FC[241], x01_FC[242], x01_FC[243], x01_FC[244], x01_FC[245], x01_FC[246], x01_FC[247], x01_FC[248],
+ // </editor-fold>
+ x01_FC[249], x01_FC[250], x01_FC[251], xFD);
+ }
@Test
public void test254() throws Throwable {
@@ -933,6 +1129,8 @@
test254(mh, a, r0);
MethodHandle mh_CA = MH_hashArguments_VA.asFixedArity().asCollector(Object[].class, ARITY);
test254(mh_CA, a, r0);
+ MethodHandle mh_a = MethodHandles.lookup().findStatic(BigArityTest.class, "hashArguments_"+ARITY+"_a", MT_A).asCollector(1, Object[].class, ARITY-2);
+ test254(mh_a, a, r0);
}
public void test254(MethodHandle mh, Object[] a, Object r0) throws Throwable {
Object r;
@@ -1094,6 +1292,43 @@
// </editor-fold>
xF8, xF9, xFA, xFB, xFC, xFD, xFE);
}
+ static Object hashArguments_255_a(Object x00, Object[] x01_FD, Object xFE) {
+ return Objects.hash(
+ // <editor-fold defaultstate="collapsed" desc="x00, x01_FD[0], x01_FD[1], x01_FD[2], ...">
+ x00, x01_FD[0], x01_FD[1], x01_FD[2], x01_FD[3], x01_FD[4], x01_FD[5], x01_FD[6], x01_FD[7], x01_FD[8],
+ x01_FD[9], x01_FD[10], x01_FD[11], x01_FD[12], x01_FD[13], x01_FD[14], x01_FD[15], x01_FD[16],
+ x01_FD[17], x01_FD[18], x01_FD[19], x01_FD[20], x01_FD[21], x01_FD[22], x01_FD[23], x01_FD[24],
+ x01_FD[25], x01_FD[26], x01_FD[27], x01_FD[28], x01_FD[29], x01_FD[30], x01_FD[31], x01_FD[32],
+ x01_FD[33], x01_FD[34], x01_FD[35], x01_FD[36], x01_FD[37], x01_FD[38], x01_FD[39], x01_FD[40],
+ x01_FD[41], x01_FD[42], x01_FD[43], x01_FD[44], x01_FD[45], x01_FD[46], x01_FD[47], x01_FD[48],
+ x01_FD[49], x01_FD[50], x01_FD[51], x01_FD[52], x01_FD[53], x01_FD[54], x01_FD[55], x01_FD[56],
+ x01_FD[57], x01_FD[58], x01_FD[59], x01_FD[60], x01_FD[61], x01_FD[62], x01_FD[63], x01_FD[64],
+ x01_FD[65], x01_FD[66], x01_FD[67], x01_FD[68], x01_FD[69], x01_FD[70], x01_FD[71], x01_FD[72],
+ x01_FD[73], x01_FD[74], x01_FD[75], x01_FD[76], x01_FD[77], x01_FD[78], x01_FD[79], x01_FD[80],
+ x01_FD[81], x01_FD[82], x01_FD[83], x01_FD[84], x01_FD[85], x01_FD[86], x01_FD[87], x01_FD[88],
+ x01_FD[89], x01_FD[90], x01_FD[91], x01_FD[92], x01_FD[93], x01_FD[94], x01_FD[95], x01_FD[96],
+ x01_FD[97], x01_FD[98], x01_FD[99], x01_FD[100], x01_FD[101], x01_FD[102], x01_FD[103], x01_FD[104],
+ x01_FD[105], x01_FD[106], x01_FD[107], x01_FD[108], x01_FD[109], x01_FD[110], x01_FD[111], x01_FD[112],
+ x01_FD[113], x01_FD[114], x01_FD[115], x01_FD[116], x01_FD[117], x01_FD[118], x01_FD[119], x01_FD[120],
+ x01_FD[121], x01_FD[122], x01_FD[123], x01_FD[124], x01_FD[125], x01_FD[126], x01_FD[127], x01_FD[128],
+ x01_FD[129], x01_FD[130], x01_FD[131], x01_FD[132], x01_FD[133], x01_FD[134], x01_FD[135], x01_FD[136],
+ x01_FD[137], x01_FD[138], x01_FD[139], x01_FD[140], x01_FD[141], x01_FD[142], x01_FD[143], x01_FD[144],
+ x01_FD[145], x01_FD[146], x01_FD[147], x01_FD[148], x01_FD[149], x01_FD[150], x01_FD[151], x01_FD[152],
+ x01_FD[153], x01_FD[154], x01_FD[155], x01_FD[156], x01_FD[157], x01_FD[158], x01_FD[159], x01_FD[160],
+ x01_FD[161], x01_FD[162], x01_FD[163], x01_FD[164], x01_FD[165], x01_FD[166], x01_FD[167], x01_FD[168],
+ x01_FD[169], x01_FD[170], x01_FD[171], x01_FD[172], x01_FD[173], x01_FD[174], x01_FD[175], x01_FD[176],
+ x01_FD[177], x01_FD[178], x01_FD[179], x01_FD[180], x01_FD[181], x01_FD[182], x01_FD[183], x01_FD[184],
+ x01_FD[185], x01_FD[186], x01_FD[187], x01_FD[188], x01_FD[189], x01_FD[190], x01_FD[191], x01_FD[192],
+ x01_FD[193], x01_FD[194], x01_FD[195], x01_FD[196], x01_FD[197], x01_FD[198], x01_FD[199], x01_FD[200],
+ x01_FD[201], x01_FD[202], x01_FD[203], x01_FD[204], x01_FD[205], x01_FD[206], x01_FD[207], x01_FD[208],
+ x01_FD[209], x01_FD[210], x01_FD[211], x01_FD[212], x01_FD[213], x01_FD[214], x01_FD[215], x01_FD[216],
+ x01_FD[217], x01_FD[218], x01_FD[219], x01_FD[220], x01_FD[221], x01_FD[222], x01_FD[223], x01_FD[224],
+ x01_FD[225], x01_FD[226], x01_FD[227], x01_FD[228], x01_FD[229], x01_FD[230], x01_FD[231], x01_FD[232],
+ x01_FD[233], x01_FD[234], x01_FD[235], x01_FD[236], x01_FD[237], x01_FD[238], x01_FD[239], x01_FD[240],
+ x01_FD[241], x01_FD[242], x01_FD[243], x01_FD[244], x01_FD[245], x01_FD[246], x01_FD[247], x01_FD[248],
+ // </editor-fold>
+ x01_FD[249], x01_FD[250], x01_FD[251], x01_FD[252], xFE);
+ }
@Test
public void test255() throws Throwable {
@@ -1163,5 +1398,38 @@
} catch (IllegalArgumentException ex) {
System.out.println("OK: "+ex);
}
+ MethodHandle mh_a;
+ try {
+ mh_a = MethodHandles.lookup().findStatic(BigArityTest.class, "hashArguments_"+ARITY+"_a", MT_A).asCollector(1, Object[].class, ARITY-2);
+ throw new AssertionError("should not create an arity 255 collector method handle");
+ } catch (IllegalArgumentException ex) {
+ System.out.println("OK: "+ex);
+ mh_a = MethodHandles.lookup().findStatic(BigArityTest.class, "hashArguments_"+ARITY+"_a", MT_A).asCollector(1, Object[].class, ARITY-3);
+ }
+ try {
+ r = mh_a.invokeExact(
+ // <editor-fold defaultstate="collapsed" desc="a[0x00], a[0x01], a[0x02], a[0x03], a[0x04], ...">
+ a[0x00], a[0x01], a[0x02], a[0x03], a[0x04], a[0x05], a[0x06], a[0x07], a[0x08], a[0x09], a[0x0A], a[0x0B], a[0x0C], a[0x0D], a[0x0E], a[0x0F],
+ a[0x10], a[0x11], a[0x12], a[0x13], a[0x14], a[0x15], a[0x16], a[0x17], a[0x18], a[0x19], a[0x1A], a[0x1B], a[0x1C], a[0x1D], a[0x1E], a[0x1F],
+ a[0x20], a[0x21], a[0x22], a[0x23], a[0x24], a[0x25], a[0x26], a[0x27], a[0x28], a[0x29], a[0x2A], a[0x2B], a[0x2C], a[0x2D], a[0x2E], a[0x2F],
+ a[0x30], a[0x31], a[0x32], a[0x33], a[0x34], a[0x35], a[0x36], a[0x37], a[0x38], a[0x39], a[0x3A], a[0x3B], a[0x3C], a[0x3D], a[0x3E], a[0x3F],
+ a[0x40], a[0x41], a[0x42], a[0x43], a[0x44], a[0x45], a[0x46], a[0x47], a[0x48], a[0x49], a[0x4A], a[0x4B], a[0x4C], a[0x4D], a[0x4E], a[0x4F],
+ a[0x50], a[0x51], a[0x52], a[0x53], a[0x54], a[0x55], a[0x56], a[0x57], a[0x58], a[0x59], a[0x5A], a[0x5B], a[0x5C], a[0x5D], a[0x5E], a[0x5F],
+ a[0x60], a[0x61], a[0x62], a[0x63], a[0x64], a[0x65], a[0x66], a[0x67], a[0x68], a[0x69], a[0x6A], a[0x6B], a[0x6C], a[0x6D], a[0x6E], a[0x6F],
+ a[0x70], a[0x71], a[0x72], a[0x73], a[0x74], a[0x75], a[0x76], a[0x77], a[0x78], a[0x79], a[0x7A], a[0x7B], a[0x7C], a[0x7D], a[0x7E], a[0x7F],
+ a[0x80], a[0x81], a[0x82], a[0x83], a[0x84], a[0x85], a[0x86], a[0x87], a[0x88], a[0x89], a[0x8A], a[0x8B], a[0x8C], a[0x8D], a[0x8E], a[0x8F],
+ a[0x90], a[0x91], a[0x92], a[0x93], a[0x94], a[0x95], a[0x96], a[0x97], a[0x98], a[0x99], a[0x9A], a[0x9B], a[0x9C], a[0x9D], a[0x9E], a[0x9F],
+ a[0xA0], a[0xA1], a[0xA2], a[0xA3], a[0xA4], a[0xA5], a[0xA6], a[0xA7], a[0xA8], a[0xA9], a[0xAA], a[0xAB], a[0xAC], a[0xAD], a[0xAE], a[0xAF],
+ a[0xB0], a[0xB1], a[0xB2], a[0xB3], a[0xB4], a[0xB5], a[0xB6], a[0xB7], a[0xB8], a[0xB9], a[0xBA], a[0xBB], a[0xBC], a[0xBD], a[0xBE], a[0xBF],
+ a[0xC0], a[0xC1], a[0xC2], a[0xC3], a[0xC4], a[0xC5], a[0xC6], a[0xC7], a[0xC8], a[0xC9], a[0xCA], a[0xCB], a[0xCC], a[0xCD], a[0xCE], a[0xCF],
+ a[0xD0], a[0xD1], a[0xD2], a[0xD3], a[0xD4], a[0xD5], a[0xD6], a[0xD7], a[0xD8], a[0xD9], a[0xDA], a[0xDB], a[0xDC], a[0xDD], a[0xDE], a[0xDF],
+ a[0xE0], a[0xE1], a[0xE2], a[0xE3], a[0xE4], a[0xE5], a[0xE6], a[0xE7], a[0xE8], a[0xE9], a[0xEA], a[0xEB], a[0xEC], a[0xED], a[0xEE], a[0xEF],
+ a[0xF0], a[0xF1], a[0xF2], a[0xF3], a[0xF4], a[0xF5], a[0xF6], a[0xF7],
+ // </editor-fold>
+ a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC], a[0xFD], a[0xFE]);
+ throw new AssertionError("should not call an arity 255 collector method handle");
+ } catch (LinkageError ex) {
+ System.out.println("OK: "+ex);
+ }
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/CompileThresholdBootstrapTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8143232
+ * @summary Test verifies that LF bootstraps properly when run with COMPILE_THRESHOLD set
+ * @compile CompileThresholdBootstrapTest.java
+ * @run testng/othervm -Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=30 test.java.lang.invoke.CompileThresholdBootstrapTest
+ */
+package test.java.lang.invoke;
+
+import java.lang.invoke.MethodHandles;
+import org.testng.*;
+import org.testng.annotations.*;
+
+public final class CompileThresholdBootstrapTest {
+
+ @Test
+ public void testBootstrap() throws Throwable {
+ Assert.assertEquals(0, (int)MethodHandles.constant(int.class, (int)0).invokeExact());
+ }
+
+ public static void main(String ... args) {
+ try {
+ CompileThresholdBootstrapTest test = new CompileThresholdBootstrapTest();
+ test.testBootstrap();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/FindClassSecurityManager.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @run main/othervm/policy=findclass.security.policy/secure=java.lang.SecurityManager -ea -esa test.java.lang.invoke.FindClassSecurityManager
+ */
+
+package test.java.lang.invoke;
+
+import java.lang.invoke.MethodHandles;
+
+public class FindClassSecurityManager {
+ public static void main(String[] args) throws Throwable {
+ assert null != System.getSecurityManager();
+ Class<?> thisClass = FindClassSecurityManager.class;
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ Class<?> lookedUp = lookup.findClass(thisClass.getName());
+ assert thisClass == lookedUp;
+ Class<?> accessed = lookup.accessClass(thisClass);
+ assert thisClass == accessed;
+ }
+}
--- a/jdk/test/java/lang/invoke/MethodHandlesTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/lang/invoke/MethodHandlesTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -32,6 +32,7 @@
import test.java.lang.invoke.remote.RemoteExample;
import java.lang.invoke.*;
+import static java.lang.invoke.MethodType.methodType;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.*;
import java.util.*;
@@ -448,6 +449,7 @@
}
public static interface IntExample {
public void v0();
+ public default void vd() { called("vd", this); }
public static class Impl implements IntExample {
public void v0() { called("Int/v0", this); }
final String name;
@@ -719,9 +721,10 @@
public void testFindSpecial0() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("findSpecial");
- testFindSpecial(SubExample.class, Example.class, void.class, "v0");
- testFindSpecial(SubExample.class, Example.class, void.class, "pkg_v0");
- testFindSpecial(RemoteExample.class, PubExample.class, void.class, "Pub/pro_v0");
+ testFindSpecial(SubExample.class, Example.class, void.class, false, "v0");
+ testFindSpecial(SubExample.class, Example.class, void.class, false, "pkg_v0");
+ testFindSpecial(RemoteExample.class, PubExample.class, void.class, false, "Pub/pro_v0");
+ testFindSpecial(Example.class, IntExample.class, void.class, true, "vd");
// Do some negative testing:
for (Lookup lookup : new Lookup[]{ PRIVATE, EXAMPLE, PACKAGE, PUBLIC }) {
testFindSpecial(false, lookup, Object.class, Example.class, void.class, "v0");
@@ -729,11 +732,12 @@
testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", int.class);
testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", Void.class);
testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "s0");
+ testFindSpecial(false, lookup, Example.class, IntExample.class, void.class, "v0");
}
}
void testFindSpecial(Class<?> specialCaller,
- Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
+ Class<?> defc, Class<?> ret, boolean dflt, String name, Class<?>... params) throws Throwable {
if (specialCaller == RemoteExample.class) {
testFindSpecial(false, EXAMPLE, specialCaller, defc, ret, name, params);
testFindSpecial(false, PRIVATE, specialCaller, defc, ret, name, params);
@@ -742,11 +746,11 @@
testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params);
return;
}
- testFindSpecial(true, EXAMPLE, specialCaller, defc, ret, name, params);
- testFindSpecial(true, PRIVATE, specialCaller, defc, ret, name, params);
- testFindSpecial(false, PACKAGE, specialCaller, defc, ret, name, params);
- testFindSpecial(false, SUBCLASS, specialCaller, defc, ret, name, params);
- testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params);
+ testFindSpecial(true, EXAMPLE, specialCaller, defc, ret, name, params);
+ testFindSpecial(true, PRIVATE, specialCaller, defc, ret, name, params);
+ testFindSpecial(false || dflt, PACKAGE, specialCaller, defc, ret, name, params);
+ testFindSpecial(false, SUBCLASS, specialCaller, defc, ret, name, params);
+ testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params);
}
void testFindSpecial(boolean positive, Lookup lookup, Class<?> specialCaller,
Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
@@ -1834,6 +1838,7 @@
@Test // SLOW
public void testSpreadArguments() throws Throwable {
CodeCacheOverflowProcessor.runMHTest(this::testSpreadArguments0);
+ CodeCacheOverflowProcessor.runMHTest(this::testSpreadArguments1);
}
public void testSpreadArguments0() throws Throwable {
@@ -1842,26 +1847,97 @@
for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
if (verbosity >= 3)
System.out.println("spreadArguments "+argType);
+ Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass();
for (int nargs = 0; nargs < 50; nargs++) {
if (CAN_TEST_LIGHTLY && nargs > 11) break;
for (int pos = 0; pos <= nargs; pos++) {
if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
continue;
- testSpreadArguments(argType, pos, nargs);
+ testSpreadArguments(argType, arrayType, pos, nargs);
}
}
}
}
- public void testSpreadArguments(Class<?> argType, int pos, int nargs) throws Throwable {
+ public void testSpreadArguments(Class<?> argType, Class<?> arrayType, int pos, int nargs) throws Throwable {
countTest();
- Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass();
MethodHandle target2 = varargsArray(arrayType, nargs);
MethodHandle target = target2.asType(target2.type().generic());
if (verbosity >= 3)
System.out.println("spread into "+target2+" ["+pos+".."+nargs+"]");
Object[] args = randomArgs(target2.type().parameterArray());
// make sure the target does what we think it does:
+ checkTarget(argType, pos, nargs, target, args);
+ List<Class<?>> newParams = new ArrayList<>(target2.type().parameterList());
+ { // modify newParams in place
+ List<Class<?>> spreadParams = newParams.subList(pos, nargs);
+ spreadParams.clear(); spreadParams.add(arrayType);
+ }
+ MethodType newType = MethodType.methodType(arrayType, newParams);
+ MethodHandle result = target2.asSpreader(arrayType, nargs-pos);
+ assert(result.type() == newType) : Arrays.asList(result, newType);
+ result = result.asType(newType.generic());
+ Object returnValue;
+ if (pos == 0) {
+ Object args2 = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length));
+ returnValue = result.invokeExact(args2);
+ } else {
+ Object[] args1 = Arrays.copyOfRange(args, 0, pos+1);
+ args1[pos] = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length));
+ returnValue = result.invokeWithArguments(args1);
+ }
+ checkReturnValue(argType, args, result, returnValue);
+ }
+ public void testSpreadArguments1() throws Throwable {
+ if (CAN_SKIP_WORKING) return;
+ startTest("spreadArguments/pos");
+ for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
+ if (verbosity >= 3)
+ System.out.println("spreadArguments "+argType);
+ Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass();
+ for (int nargs = 0; nargs < 50; nargs++) {
+ if (CAN_TEST_LIGHTLY && nargs > 11) break;
+ for (int pos = 0; pos <= nargs; pos++) {
+ if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
+ if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
+ continue;
+ for (int spr = 1; spr < nargs - pos; ++spr) {
+ if (spr > 4 && spr != 7 && spr != 11 && spr != 20 && spr < nargs - pos - 4) continue;
+ testSpreadArguments(argType, arrayType, pos, spr, nargs);
+ }
+ }
+ }
+ }
+ }
+ public void testSpreadArguments(Class<?> argType, Class<?> arrayType, int pos, int spread, int nargs) throws Throwable {
+ countTest();
+ MethodHandle target2 = varargsArray(arrayType, nargs);
+ MethodHandle target = target2.asType(target2.type().generic());
+ if (verbosity >= 3)
+ System.out.println("spread into " + target2 + " [" + pos + ".." + (pos + spread) + "[");
+ Object[] args = randomArgs(target2.type().parameterArray());
+ // make sure the target does what we think it does:
+ checkTarget(argType, pos, nargs, target, args);
+ List<Class<?>> newParams = new ArrayList<>(target2.type().parameterList());
+ { // modify newParams in place
+ List<Class<?>> spreadParams = newParams.subList(pos, pos + spread);
+ spreadParams.clear();
+ spreadParams.add(arrayType);
+ }
+ MethodType newType = MethodType.methodType(arrayType, newParams);
+ MethodHandle result = target2.asSpreader(pos, arrayType, spread);
+ assert (result.type() == newType) : Arrays.asList(result, newType);
+ result = result.asType(newType.generic());
+ // args1 has nargs-spread entries, plus one for the to-be-spread array
+ int args1Length = nargs - (spread - 1);
+ Object[] args1 = new Object[args1Length];
+ System.arraycopy(args, 0, args1, 0, pos);
+ args1[pos] = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, pos + spread));
+ System.arraycopy(args, pos + spread, args1, pos + 1, nargs - spread - pos);
+ Object returnValue = result.invokeWithArguments(args1);
+ checkReturnValue(argType, args, result, returnValue);
+ }
+ private static void checkTarget(Class<?> argType, int pos, int nargs, MethodHandle target, Object[] args) throws Throwable {
if (pos == 0 && nargs < 5 && !argType.isPrimitive()) {
Object[] check = (Object[]) target.invokeWithArguments(args);
assertArrayEquals(args, check);
@@ -1880,24 +1956,8 @@
break;
}
}
- List<Class<?>> newParams = new ArrayList<>(target2.type().parameterList());
- { // modify newParams in place
- List<Class<?>> spreadParams = newParams.subList(pos, nargs);
- spreadParams.clear(); spreadParams.add(arrayType);
- }
- MethodType newType = MethodType.methodType(arrayType, newParams);
- MethodHandle result = target2.asSpreader(arrayType, nargs-pos);
- assert(result.type() == newType) : Arrays.asList(result, newType);
- result = result.asType(newType.generic());
- Object returnValue;
- if (pos == 0) {
- Object args2 = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length));
- returnValue = result.invokeExact(args2);
- } else {
- Object[] args1 = Arrays.copyOfRange(args, 0, pos+1);
- args1[pos] = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length));
- returnValue = result.invokeWithArguments(args1);
- }
+ }
+ private static void checkReturnValue(Class<?> argType, Object[] args, MethodHandle result, Object returnValue) {
String argstr = Arrays.toString(args);
if (!argType.isPrimitive()) {
Object[] rv = (Object[]) returnValue;
@@ -1932,6 +1992,7 @@
@Test // SLOW
public void testAsCollector() throws Throwable {
CodeCacheOverflowProcessor.runMHTest(this::testAsCollector0);
+ CodeCacheOverflowProcessor.runMHTest(this::testAsCollector1);
}
public void testAsCollector0() throws Throwable {
@@ -1974,6 +2035,51 @@
// collectedArgs[pos] = Arrays.asList((Object[]) collectedArgs[pos]);
assertArrayEquals(collectedArgs, returnValue);
}
+ public void testAsCollector1() throws Throwable {
+ if (CAN_SKIP_WORKING) return;
+ startTest("asCollector/pos");
+ for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
+ if (verbosity >= 3)
+ System.out.println("asCollector/pos "+argType);
+ for (int nargs = 0; nargs < 50; nargs++) {
+ if (CAN_TEST_LIGHTLY && nargs > 11) break;
+ for (int pos = 0; pos <= nargs; pos++) {
+ if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
+ if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
+ continue;
+ for (int coll = 1; coll < nargs - pos; ++coll) {
+ if (coll > 4 && coll != 7 && coll != 11 && coll != 20 && coll < nargs - pos - 4) continue;
+ testAsCollector(argType, pos, coll, nargs);
+ }
+ }
+ }
+ }
+ }
+ public void testAsCollector(Class<?> argType, int pos, int collect, int nargs) throws Throwable {
+ countTest();
+ // fake up a MH with the same type as the desired adapter:
+ MethodHandle fake = varargsArray(nargs);
+ fake = changeArgTypes(fake, argType);
+ MethodType newType = fake.type();
+ Object[] args = randomArgs(newType.parameterArray());
+ // here is what should happen:
+ // new arg list has "collect" less arguments, but one extra for collected arguments array
+ int collectedLength = nargs-(collect-1);
+ Object[] collectedArgs = new Object[collectedLength];
+ System.arraycopy(args, 0, collectedArgs, 0, pos);
+ collectedArgs[pos] = Arrays.copyOfRange(args, pos, pos+collect);
+ System.arraycopy(args, pos+collect, collectedArgs, pos+1, args.length-(pos+collect));
+ // here is the MH which will witness the collected argument part (not tail!):
+ MethodHandle target = varargsArray(collectedLength);
+ target = changeArgTypes(target, 0, pos, argType);
+ target = changeArgTypes(target, pos, pos+1, Object[].class);
+ target = changeArgTypes(target, pos+1, collectedLength, argType);
+ if (verbosity >= 3)
+ System.out.println("collect "+collect+" from "+Arrays.asList(args)+" ["+pos+".."+(pos+collect)+"[");
+ MethodHandle result = target.asCollector(pos, Object[].class, collect).asType(newType);
+ Object[] returnValue = (Object[]) result.invokeWithArguments(args);
+ assertArrayEquals(collectedArgs, returnValue);
+ }
@Test // SLOW
public void testInsertArguments() throws Throwable {
@@ -2117,21 +2223,29 @@
public void testCollectArguments0() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("collectArguments");
- testFoldOrCollectArguments(true);
+ testFoldOrCollectArguments(true, false);
}
@Test
public void testFoldArguments() throws Throwable {
CodeCacheOverflowProcessor.runMHTest(this::testFoldArguments0);
+ CodeCacheOverflowProcessor.runMHTest(this::testFoldArguments1);
}
public void testFoldArguments0() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("foldArguments");
- testFoldOrCollectArguments(false);
+ testFoldOrCollectArguments(false, false);
}
- void testFoldOrCollectArguments(boolean isCollect) throws Throwable {
+ public void testFoldArguments1() throws Throwable {
+ if (CAN_SKIP_WORKING) return;
+ startTest("foldArguments/pos");
+ testFoldOrCollectArguments(false, true);
+ }
+
+ void testFoldOrCollectArguments(boolean isCollect, boolean withFoldPos) throws Throwable {
+ assert !(isCollect && withFoldPos); // exclude illegal argument combination
for (Class<?> lastType : new Class<?>[]{ Object.class, String.class, int.class }) {
for (Class<?> collectType : new Class<?>[]{ Object.class, String.class, int.class, void.class }) {
int maxArity = 10;
@@ -2146,7 +2260,7 @@
if (!mixArgs(argTypes, mix, argTypesSeen)) continue;
for (int collect = 0; collect <= nargs; collect++) {
for (int pos = 0; pos <= nargs - collect; pos++) {
- testFoldOrCollectArguments(argTypes, pos, collect, collectType, lastType, isCollect);
+ testFoldOrCollectArguments(argTypes, pos, collect, collectType, lastType, isCollect, withFoldPos);
}
}
}
@@ -2186,13 +2300,14 @@
int pos, int fold, // position and length of the folded arguments
Class<?> combineType, // type returned from the combiner
Class<?> lastType, // type returned from the target
- boolean isCollect) throws Throwable {
+ boolean isCollect,
+ boolean withFoldPos) throws Throwable {
int nargs = argTypes.size();
- if (pos != 0 && !isCollect) return; // can fold only at pos=0 for now
+ if (pos != 0 && !isCollect && !withFoldPos) return; // test MethodHandles.foldArguments(MH,MH) only for pos=0
countTest();
List<Class<?>> combineArgTypes = argTypes.subList(pos, pos + fold);
List<Class<?>> targetArgTypes = new ArrayList<>(argTypes);
- if (isCollect) // does targret see arg[pos..pos+cc-1]?
+ if (isCollect) // does target see arg[pos..pos+cc-1]?
targetArgTypes.subList(pos, pos + fold).clear();
if (combineType != void.class)
targetArgTypes.add(pos, combineType);
@@ -2205,7 +2320,7 @@
if (isCollect)
target2 = MethodHandles.collectArguments(target, pos, combine);
else
- target2 = MethodHandles.foldArguments(target, combine);
+ target2 = withFoldPos ? MethodHandles.foldArguments(target, pos, combine) : MethodHandles.foldArguments(target, combine);
// Simulate expected effect of combiner on arglist:
List<Object> expectedList = new ArrayList<>(argsToPass);
List<Object> argsToFold = expectedList.subList(pos, pos + fold);
@@ -2541,6 +2656,203 @@
}
@Test
+ public void testGenericLoopCombinator() throws Throwable {
+ CodeCacheOverflowProcessor.runMHTest(this::testGenericLoopCombinator0);
+ }
+ public void testGenericLoopCombinator0() throws Throwable {
+ if (CAN_SKIP_WORKING) return;
+ startTest("loop");
+ // Test as follows:
+ // * Have an increasing number of loop-local state. Local state type diversity grows with the number.
+ // * Initializers set the starting value of loop-local state from the corresponding loop argument.
+ // * For each local state element, there is a predicate - for all state combinations, exercise all predicates.
+ // * Steps modify each local state element in each iteration.
+ // * Finalizers group all local state elements into a resulting array. Verify end values.
+ // * Exercise both pre- and post-checked loops.
+ // Local state types, start values, predicates, and steps:
+ // * int a, 0, a < 7, a = a + 1
+ // * double b, 7.0, b > 0.5, b = b / 2.0
+ // * String c, "start", c.length <= 9, c = c + a
+ final Class<?>[] argTypes = new Class<?>[] {int.class, double.class, String.class};
+ final Object[][] args = new Object[][] {
+ new Object[]{0 },
+ new Object[]{0, 7.0 },
+ new Object[]{0, 7.0, "start"}
+ };
+ // These are the expected final state tuples for argument type tuple / predicate combinations, for pre- and
+ // post-checked loops:
+ final Object[][] preCheckedResults = new Object[][] {
+ new Object[]{7 }, // (int) / int
+ new Object[]{7, 0.0546875 }, // (int,double) / int
+ new Object[]{5, 0.4375 }, // (int,double) / double
+ new Object[]{7, 0.0546875, "start1234567"}, // (int,double,String) / int
+ new Object[]{5, 0.4375, "start1234" }, // (int,double,String) / double
+ new Object[]{6, 0.109375, "start12345" } // (int,double,String) / String
+ };
+ final Object[][] postCheckedResults = new Object[][] {
+ new Object[]{7 }, // (int) / int
+ new Object[]{7, 0.109375 }, // (int,double) / int
+ new Object[]{4, 0.4375 }, // (int,double) / double
+ new Object[]{7, 0.109375, "start123456"}, // (int,double,String) / int
+ new Object[]{4, 0.4375, "start123" }, // (int,double,String) / double
+ new Object[]{5, 0.21875, "start12345" } // (int,double,String) / String
+ };
+ final Lookup l = MethodHandles.lookup();
+ final Class<?> MHT = MethodHandlesTest.class;
+ final Class<?> B = boolean.class;
+ final Class<?> I = int.class;
+ final Class<?> D = double.class;
+ final Class<?> S = String.class;
+ final MethodHandle hip = l.findStatic(MHT, "loopIntPred", methodType(B, I));
+ final MethodHandle hdp = l.findStatic(MHT, "loopDoublePred", methodType(B, I, D));
+ final MethodHandle hsp = l.findStatic(MHT, "loopStringPred", methodType(B, I, D, S));
+ final MethodHandle his = l.findStatic(MHT, "loopIntStep", methodType(I, I));
+ final MethodHandle hds = l.findStatic(MHT, "loopDoubleStep", methodType(D, I, D));
+ final MethodHandle hss = l.findStatic(MHT, "loopStringStep", methodType(S, I, D, S));
+ final MethodHandle[] preds = new MethodHandle[] {hip, hdp, hsp};
+ final MethodHandle[] steps = new MethodHandle[] {his, hds, hss};
+ for (int nargs = 1, useResultsStart = 0; nargs <= argTypes.length; useResultsStart += nargs++) {
+ Class<?>[] useArgTypes = Arrays.copyOf(argTypes, nargs, Class[].class);
+ MethodHandle[] usePreds = Arrays.copyOf(preds, nargs, MethodHandle[].class);
+ MethodHandle[] useSteps = Arrays.copyOf(steps, nargs, MethodHandle[].class);
+ Object[] useArgs = args[nargs - 1];
+ Object[][] usePreCheckedResults = new Object[nargs][];
+ Object[][] usePostCheckedResults = new Object[nargs][];
+ System.arraycopy(preCheckedResults, useResultsStart, usePreCheckedResults, 0, nargs);
+ System.arraycopy(postCheckedResults, useResultsStart, usePostCheckedResults, 0, nargs);
+ testGenericLoopCombinator(nargs, useArgTypes, usePreds, useSteps, useArgs, usePreCheckedResults,
+ usePostCheckedResults);
+ }
+ }
+ void testGenericLoopCombinator(int nargs, Class<?>[] argTypes, MethodHandle[] preds, MethodHandle[] steps,
+ Object[] args, Object[][] preCheckedResults, Object[][] postCheckedResults)
+ throws Throwable {
+ List<Class<?>> lArgTypes = Arrays.asList(argTypes);
+ // Predicate and step handles are passed in as arguments, initializer and finalizer handles are constructed here
+ // from the available information.
+ MethodHandle[] inits = new MethodHandle[nargs];
+ for (int i = 0; i < nargs; ++i) {
+ MethodHandle h;
+ // Initializers are meant to return whatever they are passed at a given argument position. This means that
+ // additional arguments may have to be appended and prepended.
+ h = MethodHandles.identity(argTypes[i]);
+ if (i < nargs - 1) {
+ h = MethodHandles.dropArguments(h, 1, lArgTypes.subList(i + 1, nargs));
+ }
+ if (i > 0) {
+ h = MethodHandles.dropArguments(h, 0, lArgTypes.subList(0, i));
+ }
+ inits[i] = h;
+ }
+ // Finalizers are all meant to collect all of the loop-local state in a single array and return that. Local
+ // state is passed before the loop args. Construct such a finalizer by first taking a varargsArray collector for
+ // the number of local state arguments, and then appending the loop args as to-be-dropped arguments.
+ MethodHandle[] finis = new MethodHandle[nargs];
+ MethodHandle genericFini = MethodHandles.dropArguments(
+ varargsArray(nargs).asType(methodType(Object[].class, lArgTypes)), nargs, lArgTypes);
+ Arrays.fill(finis, genericFini);
+ // The predicate and step handles' signatures need to be extended. They currently just accept local state args;
+ // append possibly missing local state args and loop args using dropArguments.
+ for (int i = 0; i < nargs; ++i) {
+ List<Class<?>> additionalLocalStateArgTypes = lArgTypes.subList(i + 1, nargs);
+ preds[i] = MethodHandles.dropArguments(
+ MethodHandles.dropArguments(preds[i], i + 1, additionalLocalStateArgTypes), nargs, lArgTypes);
+ steps[i] = MethodHandles.dropArguments(
+ MethodHandles.dropArguments(steps[i], i + 1, additionalLocalStateArgTypes), nargs, lArgTypes);
+ }
+ // Iterate over all of the predicates, using only one of them at a time.
+ for (int i = 0; i < nargs; ++i) {
+ MethodHandle[] usePreds;
+ if (nargs == 1) {
+ usePreds = preds;
+ } else {
+ // Create an all-null preds array, and only use one predicate in this iteration. The null entries will
+ // be substituted with true predicates by the loop combinator.
+ usePreds = new MethodHandle[nargs];
+ usePreds[i] = preds[i];
+ }
+ // Go for it.
+ if (verbosity >= 3) {
+ System.out.println("calling loop for argument types " + lArgTypes + " with predicate at index " + i);
+ if (verbosity >= 5) {
+ System.out.println("predicates: " + Arrays.asList(usePreds));
+ }
+ }
+ MethodHandle[] preInits = new MethodHandle[nargs + 1];
+ MethodHandle[] prePreds = new MethodHandle[nargs + 1];
+ MethodHandle[] preSteps = new MethodHandle[nargs + 1];
+ MethodHandle[] preFinis = new MethodHandle[nargs + 1];
+ System.arraycopy(inits, 0, preInits, 1, nargs);
+ System.arraycopy(usePreds, 0, prePreds, 0, nargs); // preds are offset by 1 for pre-checked loops
+ System.arraycopy(steps, 0, preSteps, 1, nargs);
+ System.arraycopy(finis, 0, preFinis, 0, nargs); // finis are also offset by 1 for pre-checked loops
+ // Convert to clause-major form.
+ MethodHandle[][] preClauses = new MethodHandle[nargs+1][4];
+ MethodHandle[][] postClauses = new MethodHandle[nargs][4];
+ toClauseMajor(preClauses, preInits, preSteps, prePreds, preFinis);
+ toClauseMajor(postClauses, inits, steps, usePreds, finis);
+ MethodHandle pre = MethodHandles.loop(preClauses);
+ MethodHandle post = MethodHandles.loop(postClauses);
+ Object[] preResults = (Object[]) pre.invokeWithArguments(args);
+ if (verbosity >= 4) {
+ System.out.println("pre-checked: expected " + Arrays.asList(preCheckedResults[i]) + ", actual " +
+ Arrays.asList(preResults));
+ }
+ Object[] postResults = (Object[]) post.invokeWithArguments(args);
+ if (verbosity >= 4) {
+ System.out.println("post-checked: expected " + Arrays.asList(postCheckedResults[i]) + ", actual " +
+ Arrays.asList(postResults));
+ }
+ assertArrayEquals(preCheckedResults[i], preResults);
+ assertArrayEquals(postCheckedResults[i], postResults);
+ }
+ }
+ static void toClauseMajor(MethodHandle[][] clauses, MethodHandle[] init, MethodHandle[] step, MethodHandle[] pred, MethodHandle[] fini) {
+ for (int i = 0; i < clauses.length; ++i) {
+ clauses[i][0] = init[i];
+ clauses[i][1] = step[i];
+ clauses[i][2] = pred[i];
+ clauses[i][3] = fini[i];
+ }
+ }
+ static boolean loopIntPred(int a) {
+ if (verbosity >= 5) {
+ System.out.println("int pred " + a + " -> " + (a < 7));
+ }
+ return a < 7;
+ }
+ static boolean loopDoublePred(int a, double b) {
+ if (verbosity >= 5) {
+ System.out.println("double pred (a=" + a + ") " + b + " -> " + (b > 0.5));
+ }
+ return b > 0.5;
+ }
+ static boolean loopStringPred(int a, double b, String c) {
+ if (verbosity >= 5) {
+ System.out.println("String pred (a=" + a + ",b=" + b + ") " + c + " -> " + (c.length() <= 9));
+ }
+ return c.length() <= 9;
+ }
+ static int loopIntStep(int a) {
+ if (verbosity >= 5) {
+ System.out.println("int step " + a + " -> " + (a + 1));
+ }
+ return a + 1;
+ }
+ static double loopDoubleStep(int a, double b) {
+ if (verbosity >= 5) {
+ System.out.println("double step (a=" + a + ") " + b + " -> " + (b / 2.0));
+ }
+ return b / 2.0;
+ }
+ static String loopStringStep(int a, double b, String c) {
+ if (verbosity >= 5) {
+ System.out.println("String step (a=" + a + ",b=" + b + ") " + c + " -> " + (c + a));
+ }
+ return c + a;
+ }
+
+ @Test
public void testThrowException() throws Throwable {
CodeCacheOverflowProcessor.runMHTest(this::testThrowException0);
}
@@ -2576,12 +2888,107 @@
}
@Test
+ public void testTryFinally() throws Throwable {
+ CodeCacheOverflowProcessor.runMHTest(this::testTryFinally0);
+ }
+ public void testTryFinally0() throws Throwable {
+ if (CAN_SKIP_WORKING) return;
+ startTest("tryFinally");
+ String inputMessage = "returned";
+ String augmentedMessage = "augmented";
+ String thrownMessage = "thrown";
+ String rethrownMessage = "rethrown";
+ // Test these cases:
+ // * target returns, cleanup passes through
+ // * target returns, cleanup augments
+ // * target throws, cleanup augments and returns
+ // * target throws, cleanup augments and rethrows
+ MethodHandle target = MethodHandles.identity(String.class);
+ MethodHandle targetThrow = MethodHandles.dropArguments(
+ MethodHandles.throwException(String.class, Exception.class).bindTo(new Exception(thrownMessage)), 0, String.class);
+ MethodHandle cleanupPassThrough = MethodHandles.dropArguments(MethodHandles.identity(String.class), 0,
+ Throwable.class, String.class);
+ MethodHandle cleanupAugment = MethodHandles.dropArguments(MethodHandles.constant(String.class, augmentedMessage),
+ 0, Throwable.class, String.class, String.class);
+ MethodHandle cleanupCatch = MethodHandles.dropArguments(MethodHandles.constant(String.class, thrownMessage), 0,
+ Throwable.class, String.class, String.class);
+ MethodHandle cleanupThrow = MethodHandles.dropArguments(MethodHandles.throwException(String.class, Exception.class).
+ bindTo(new Exception(rethrownMessage)), 0, Throwable.class, String.class, String.class);
+ testTryFinally(target, cleanupPassThrough, inputMessage, inputMessage, false);
+ testTryFinally(target, cleanupAugment, inputMessage, augmentedMessage, false);
+ testTryFinally(targetThrow, cleanupCatch, inputMessage, thrownMessage, true);
+ testTryFinally(targetThrow, cleanupThrow, inputMessage, rethrownMessage, true);
+ // Test the same cases as above for void targets and cleanups.
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ Class<?> C = this.getClass();
+ MethodType targetType = methodType(void.class, String[].class);
+ MethodType cleanupType = methodType(void.class, Throwable.class, String[].class);
+ MethodHandle vtarget = lookup.findStatic(C, "vtarget", targetType);
+ MethodHandle vtargetThrow = lookup.findStatic(C, "vtargetThrow", targetType);
+ MethodHandle vcleanupPassThrough = lookup.findStatic(C, "vcleanupPassThrough", cleanupType);
+ MethodHandle vcleanupAugment = lookup.findStatic(C, "vcleanupAugment", cleanupType);
+ MethodHandle vcleanupCatch = lookup.findStatic(C, "vcleanupCatch", cleanupType);
+ MethodHandle vcleanupThrow = lookup.findStatic(C, "vcleanupThrow", cleanupType);
+ testTryFinally(vtarget, vcleanupPassThrough, inputMessage, inputMessage, false);
+ testTryFinally(vtarget, vcleanupAugment, inputMessage, augmentedMessage, false);
+ testTryFinally(vtargetThrow, vcleanupCatch, inputMessage, thrownMessage, true);
+ testTryFinally(vtargetThrow, vcleanupThrow, inputMessage, rethrownMessage, true);
+ }
+ void testTryFinally(MethodHandle target, MethodHandle cleanup, String input, String msg, boolean mustCatch)
+ throws Throwable {
+ countTest();
+ MethodHandle tf = MethodHandles.tryFinally(target, cleanup);
+ String result = null;
+ boolean isVoid = target.type().returnType() == void.class;
+ String[] argArray = new String[]{input};
+ try {
+ if (isVoid) {
+ tf.invoke(argArray);
+ } else {
+ result = (String) tf.invoke(input);
+ }
+ } catch (Throwable t) {
+ assertTrue(mustCatch);
+ assertEquals(msg, t.getMessage());
+ return;
+ }
+ assertFalse(mustCatch);
+ if (isVoid) {
+ assertEquals(msg, argArray[0]);
+ } else {
+ assertEquals(msg, result);
+ }
+ }
+ static void vtarget(String[] a) {
+ // naught, akin to identity
+ }
+ static void vtargetThrow(String[] a) throws Exception {
+ throw new Exception("thrown");
+ }
+ static void vcleanupPassThrough(Throwable t, String[] a) {
+ assertNull(t);
+ // naught, akin to identity
+ }
+ static void vcleanupAugment(Throwable t, String[] a) {
+ assertNull(t);
+ a[0] = "augmented";
+ }
+ static void vcleanupCatch(Throwable t, String[] a) {
+ assertNotNull(t);
+ a[0] = "caught";
+ }
+ static void vcleanupThrow(Throwable t, String[] a) throws Exception {
+ assertNotNull(t);
+ throw new Exception("rethrown");
+ }
+
+ @Test
public void testInterfaceCast() throws Throwable {
CodeCacheOverflowProcessor.runMHTest(this::testInterfaceCast0);
}
public void testInterfaceCast0() throws Throwable {
- //if (CAN_SKIP_WORKING) return;
+ if (CAN_SKIP_WORKING) return;
startTest("interfaceCast");
assert( (((Object)"foo") instanceof CharSequence));
assert(!(((Object)"foo") instanceof Iterable));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/T8139885.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,1082 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @run testng/othervm -ea -esa test.java.lang.invoke.T8139885
+ */
+
+package test.java.lang.invoke;
+
+import java.io.StringWriter;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+import java.util.*;
+
+import static java.lang.invoke.MethodType.methodType;
+
+import static org.testng.AssertJUnit.*;
+
+import org.testng.annotations.*;
+
+/**
+ * Example-scale and negative tests for JEP 274 extensions.
+ */
+public class T8139885 {
+
+ static final Lookup LOOKUP = MethodHandles.lookup();
+
+ //
+ // Tests.
+ //
+
+ @Test
+ public static void testLoopFac() throws Throwable {
+ MethodHandle[] counterClause = new MethodHandle[]{Fac.MH_zero, Fac.MH_inc};
+ MethodHandle[] accumulatorClause = new MethodHandle[]{Fac.MH_one, Fac.MH_mult, Fac.MH_pred, Fac.MH_fin};
+ MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);
+ assertEquals(Fac.MT_fac, loop.type());
+ assertEquals(120, loop.invoke(5));
+ }
+
+ @Test
+ public static void testLoopFacNullInit() throws Throwable {
+ // null initializer for counter, should initialize to 0
+ MethodHandle[] counterClause = new MethodHandle[]{null, Fac.MH_inc};
+ MethodHandle[] accumulatorClause = new MethodHandle[]{Fac.MH_one, Fac.MH_mult, Fac.MH_pred, Fac.MH_fin};
+ MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);
+ assertEquals(Fac.MT_fac, loop.type());
+ assertEquals(120, loop.invoke(5));
+ }
+
+ @Test
+ public static void testLoopVoid1() throws Throwable {
+ // construct a post-checked loop that only does one iteration and has a void body and void local state
+ MethodHandle loop = MethodHandles.loop(new MethodHandle[]{Empty.MH_f, Empty.MH_f, Empty.MH_pred, null});
+ assertEquals(MethodType.methodType(void.class), loop.type());
+ loop.invoke();
+ }
+
+ @Test
+ public static void testLoopVoid2() throws Throwable {
+ // construct a post-checked loop that only does one iteration and has a void body and void local state,
+ // initialized implicitly from the step type
+ MethodHandle loop = MethodHandles.loop(new MethodHandle[]{null, Empty.MH_f, Empty.MH_pred, null});
+ assertEquals(MethodType.methodType(void.class), loop.type());
+ loop.invoke();
+ }
+
+ @Test
+ public static void testLoopFacWithVoidState() throws Throwable {
+ // like testLoopFac, but with additional void state that outputs a dot
+ MethodHandle[] counterClause = new MethodHandle[]{Fac.MH_zero, Fac.MH_inc};
+ MethodHandle[] accumulatorClause = new MethodHandle[]{Fac.MH_one, Fac.MH_mult, Fac.MH_pred, Fac.MH_fin};
+ MethodHandle[] dotClause = new MethodHandle[]{null, Fac.MH_dot};
+ MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause, dotClause);
+ assertEquals(Fac.MT_fac, loop.type());
+ assertEquals(120, loop.invoke(5));
+ }
+
+ @Test
+ public static void testLoopNegative() throws Throwable {
+ MethodHandle mh_loop =
+ LOOKUP.findStatic(MethodHandles.class, "loop", methodType(MethodHandle.class, MethodHandle[][].class));
+ MethodHandle i0 = MethodHandles.constant(int.class, 0);
+ MethodHandle ii = MethodHandles.dropArguments(i0, 0, int.class, int.class);
+ MethodHandle id = MethodHandles.dropArguments(i0, 0, int.class, double.class);
+ MethodHandle i3 = MethodHandles.dropArguments(i0, 0, int.class, int.class, int.class);
+ List<MethodHandle> inits = Arrays.asList(ii, id, i3);
+ List<Class<?>> ints = Arrays.asList(int.class, int.class, int.class);
+ List<MethodHandle> finis = Arrays.asList(Fac.MH_fin, Fac.MH_inc, Counted.MH_step);
+ List<MethodHandle> preds1 = Arrays.asList(null, null, null);
+ List<MethodHandle> preds2 = Arrays.asList(null, Fac.MH_fin, null);
+ MethodHandle eek = MethodHandles.dropArguments(i0, 0, int.class, int.class, double.class);
+ List<MethodHandle> nesteps = Arrays.asList(Fac.MH_inc, eek, Fac.MH_dot);
+ List<MethodHandle> nepreds = Arrays.asList(null, Fac.MH_pred, null);
+ List<MethodHandle> nefinis = Arrays.asList(null, Fac.MH_fin, null);
+ MethodHandle[][][] cases = {
+ null,
+ {},
+ {{null, Fac.MH_inc}, {Fac.MH_one, null, Fac.MH_mult, Fac.MH_pred, Fac.MH_fin}},
+ {{null, Fac.MH_inc}, null},
+ {{Fac.MH_zero, Fac.MH_dot}},
+ {{ii}, {id}, {i3}},
+ {{null, Fac.MH_inc, null, Fac.MH_fin}, {null, Fac.MH_inc, null, Fac.MH_inc},
+ {null, Counted.MH_start, null, Counted.MH_step}},
+ {{Fac.MH_zero, Fac.MH_inc}, {Fac.MH_one, Fac.MH_mult, null, Fac.MH_fin}, {null, Fac.MH_dot}},
+ {{Fac.MH_zero, Fac.MH_inc}, {Fac.MH_one, Fac.MH_mult, Fac.MH_fin, Fac.MH_fin}, {null, Fac.MH_dot}},
+ {{Fac.MH_zero, Fac.MH_inc}, {Fac.MH_one, eek, Fac.MH_pred, Fac.MH_fin}, {null, Fac.MH_dot}}
+ };
+ String[] messages = {
+ "null or no clauses passed",
+ "null or no clauses passed",
+ "All loop clauses must be represented as MethodHandle arrays with at most 4 elements.",
+ "null clauses are not allowed",
+ "clause 0: init and step return types must match: int != void",
+ "found non-effectively identical init parameter type lists: " + inits + " (common suffix: " + ints + ")",
+ "found non-identical finalizer return types: " + finis + " (return type: int)",
+ "no predicate found: " + preds1,
+ "predicates must have boolean return type: " + preds2,
+ "found non-effectively identical parameter type lists:\nstep: " + nesteps + "\npred: " + nepreds +
+ "\nfini: " + nefinis + " (common parameter sequence: " + ints + ")"
+ };
+ for (int i = 0; i < cases.length; ++i) {
+ boolean caught = false;
+ try {
+ mh_loop.invokeWithArguments(cases[i]);
+ } catch (IllegalArgumentException iae) {
+ assertEquals(messages[i], iae.getMessage());
+ caught = true;
+ }
+ assertTrue(caught);
+ }
+ }
+
+ @Test
+ public static void testWhileLoop() throws Throwable {
+ // int i = 0; while (i < limit) { ++i; } return i; => limit
+ MethodHandle loop = MethodHandles.whileLoop(While.MH_zero, While.MH_pred, While.MH_step);
+ assertEquals(While.MT_while, loop.type());
+ assertEquals(23, loop.invoke(23));
+ }
+
+ @Test
+ public static void testWhileLoopNoIteration() throws Throwable {
+ // a while loop that never executes its body because the predicate evaluates to false immediately
+ MethodHandle loop = MethodHandles.whileLoop(While.MH_initString, While.MH_predString, While.MH_stepString);
+ assertEquals(While.MT_string, loop.type());
+ assertEquals("a", loop.invoke());
+ }
+
+ @Test
+ public static void testDoWhileLoop() throws Throwable {
+ // int i = 0; do { ++i; } while (i < limit); return i; => limit
+ MethodHandle loop = MethodHandles.doWhileLoop(While.MH_zero, While.MH_step, While.MH_pred);
+ assertEquals(While.MT_while, loop.type());
+ assertEquals(23, loop.invoke(23));
+ }
+
+ @Test
+ public static void testWhileZip() throws Throwable {
+ MethodHandle loop = MethodHandles.doWhileLoop(While.MH_zipInitZip, While.MH_zipStep, While.MH_zipPred);
+ assertEquals(While.MT_zip, loop.type());
+ List<String> a = Arrays.asList("a", "b", "c", "d");
+ List<String> b = Arrays.asList("e", "f", "g", "h");
+ List<String> zipped = Arrays.asList("a", "e", "b", "f", "c", "g", "d", "h");
+ assertEquals(zipped, (List<String>) loop.invoke(a.iterator(), b.iterator()));
+ }
+
+ @Test
+ public static void testCountedLoop() throws Throwable {
+ // String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s; => a variation on a well known theme
+ MethodHandle fit13 = MethodHandles.constant(int.class, 13);
+ MethodHandle loop = MethodHandles.countedLoop(fit13, Counted.MH_start, Counted.MH_step);
+ assertEquals(Counted.MT_counted, loop.type());
+ assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("Lambdaman!"));
+ }
+
+ @Test
+ public static void testCountedArrayLoop() throws Throwable {
+ // int[] a = new int[]{0}; for (int i = 0; i < 13; ++i) { ++a[0]; } => a[0] == 13
+ MethodHandle fit13 = MethodHandles.dropArguments(MethodHandles.constant(int.class, 13), 0, int[].class);
+ MethodHandle loop = MethodHandles.countedLoop(fit13, null, Counted.MH_stepUpdateArray);
+ assertEquals(Counted.MT_arrayCounted, loop.type());
+ int[] a = new int[]{0};
+ loop.invoke(a);
+ assertEquals(13, a[0]);
+ }
+
+ @Test
+ public static void testCountedPrintingLoop() throws Throwable {
+ MethodHandle fit5 = MethodHandles.constant(int.class, 5);
+ MethodHandle loop = MethodHandles.countedLoop(fit5, null, Counted.MH_printHello);
+ assertEquals(Counted.MT_countedPrinting, loop.type());
+ loop.invoke();
+ }
+
+ @Test
+ public static void testCountedRangeLoop() throws Throwable {
+ // String s = "Lambdaman!"; for (int i = -5; i < 8; ++i) { s = "na " + s; } return s; => a well known theme
+ MethodHandle fitm5 = MethodHandles.dropArguments(Counted.MH_m5, 0, String.class);
+ MethodHandle fit8 = MethodHandles.dropArguments(Counted.MH_8, 0, String.class);
+ MethodHandle loop = MethodHandles.countedLoop(fitm5, fit8, Counted.MH_start, Counted.MH_step);
+ assertEquals(Counted.MT_counted, loop.type());
+ assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("Lambdaman!"));
+ }
+
+ @Test
+ public static void testIterateSum() throws Throwable {
+ // Integer[] a = new Integer[]{1,2,3,4,5,6}; int sum = 0; for (int e : a) { sum += e; } return sum; => 21
+ MethodHandle loop = MethodHandles.iteratedLoop(Iterate.MH_sumIterator, Iterate.MH_sumInit, Iterate.MH_sumStep);
+ assertEquals(Iterate.MT_sum, loop.type());
+ assertEquals(21, loop.invoke(new Integer[]{1, 2, 3, 4, 5, 6}));
+ }
+
+ @Test
+ public static void testIterateReverse() throws Throwable {
+ MethodHandle loop = MethodHandles.iteratedLoop(null, Iterate.MH_reverseInit, Iterate.MH_reverseStep);
+ assertEquals(Iterate.MT_reverse, loop.type());
+ List<String> list = Arrays.asList("a", "b", "c", "d", "e");
+ List<String> reversedList = Arrays.asList("e", "d", "c", "b", "a");
+ assertEquals(reversedList, (List<String>) loop.invoke(list));
+ }
+
+ @Test
+ public static void testIterateLength() throws Throwable {
+ MethodHandle loop = MethodHandles.iteratedLoop(null, Iterate.MH_lengthInit, Iterate.MH_lengthStep);
+ assertEquals(Iterate.MT_length, loop.type());
+ List<Double> list = Arrays.asList(23.0, 148.0, 42.0);
+ assertEquals(list.size(), (int) loop.invoke(list));
+ }
+
+ @Test
+ public static void testIterateMap() throws Throwable {
+ MethodHandle loop = MethodHandles.iteratedLoop(null, Iterate.MH_mapInit, Iterate.MH_mapStep);
+ assertEquals(Iterate.MT_map, loop.type());
+ List<String> list = Arrays.asList("Hello", "world", "!");
+ List<String> upList = Arrays.asList("HELLO", "WORLD", "!");
+ assertEquals(upList, (List<String>) loop.invoke(list));
+ }
+
+ @Test
+ public static void testIteratePrint() throws Throwable {
+ MethodHandle loop = MethodHandles.iteratedLoop(null, null, Iterate.MH_printStep);
+ assertEquals(Iterate.MT_print, loop.type());
+ loop.invoke(Arrays.asList("hello", "world"));
+ }
+
+ @Test
+ public static void testIterateNullBody() {
+ boolean caught = false;
+ try {
+ MethodHandles.iteratedLoop(MethodHandles.identity(int.class), MethodHandles.identity(int.class), null);
+ } catch (IllegalArgumentException iae) {
+ assertEquals("iterated loop body must not be null", iae.getMessage());
+ caught = true;
+ }
+ assertTrue(caught);
+ }
+
+ @Test
+ public static void testTryFinally() throws Throwable {
+ MethodHandle hello = MethodHandles.tryFinally(TryFinally.MH_greet, TryFinally.MH_exclaim);
+ assertEquals(TryFinally.MT_hello, hello.type());
+ assertEquals("Hello, world!", hello.invoke("world"));
+ }
+
+ @Test
+ public static void testTryFinallyVoid() throws Throwable {
+ MethodHandle tfVoid = MethodHandles.tryFinally(TryFinally.MH_print, TryFinally.MH_printMore);
+ assertEquals(TryFinally.MT_printHello, tfVoid.type());
+ tfVoid.invoke("world");
+ }
+
+ @Test
+ public static void testTryFinallySublist() throws Throwable {
+ MethodHandle helloMore = MethodHandles.tryFinally(TryFinally.MH_greetMore, TryFinally.MH_exclaimMore);
+ assertEquals(TryFinally.MT_moreHello, helloMore.type());
+ assertEquals("Hello, world and universe (but world first)!", helloMore.invoke("world", "universe"));
+ }
+
+ @Test
+ public static void testTryFinallyNegative() {
+ MethodHandle intid = MethodHandles.identity(int.class);
+ MethodHandle intco = MethodHandles.constant(int.class, 0);
+ MethodHandle errTarget = MethodHandles.dropArguments(intco, 0, int.class, double.class, String.class, int.class);
+ MethodHandle errCleanup = MethodHandles.dropArguments(MethodHandles.constant(int.class, 0), 0, Throwable.class,
+ int.class, double.class, Object.class);
+ MethodHandle[][] cases = {
+ {intid, MethodHandles.identity(double.class)},
+ {intid, MethodHandles.dropArguments(intid, 0, String.class)},
+ {intid, MethodHandles.dropArguments(intid, 0, Throwable.class, double.class)},
+ {errTarget, errCleanup}
+ };
+ String[] messages = {
+ "target and return types must match: double != int",
+ "cleanup first argument and Throwable must match: (String,int)int != class java.lang.Throwable",
+ "cleanup second argument and target return type must match: (Throwable,double,int)int != int",
+ "cleanup parameters after (Throwable,result) and target parameter list prefix must match: " +
+ errCleanup.type() + " != " + errTarget.type()
+ };
+ for (int i = 0; i < cases.length; ++i) {
+ boolean caught = false;
+ try {
+ MethodHandles.tryFinally(cases[i][0], cases[i][1]);
+ } catch (IllegalArgumentException iae) {
+ assertEquals(messages[i], iae.getMessage());
+ caught = true;
+ }
+ assertTrue(caught);
+ }
+ }
+
+ @Test
+ public static void testFold0a() throws Throwable {
+ // equivalence to foldArguments(MethodHandle,MethodHandle)
+ MethodHandle fold = MethodHandles.foldArguments(Fold.MH_multer, 0, Fold.MH_adder);
+ assertEquals(Fold.MT_folded1, fold.type());
+ assertEquals(720, (int) fold.invoke(3, 4, 5));
+ }
+
+ @Test
+ public static void testFold1a() throws Throwable {
+ // test foldArguments for folding position 1
+ MethodHandle fold = MethodHandles.foldArguments(Fold.MH_multer, 1, Fold.MH_adder1);
+ assertEquals(Fold.MT_folded1, fold.type());
+ assertEquals(540, (int) fold.invoke(3, 4, 5));
+ }
+
+ @Test
+ public static void testFold0b() throws Throwable {
+ // test foldArguments equivalence with multiple types
+ MethodHandle fold = MethodHandles.foldArguments(Fold.MH_str, 0, Fold.MH_comb);
+ assertEquals(Fold.MT_folded2, fold.type());
+ assertEquals(23, (int) fold.invoke("true", true, 23));
+ }
+
+ @Test
+ public static void testFold1b() throws Throwable {
+ // test folgArguments for folding position 1, with multiple types
+ MethodHandle fold = MethodHandles.foldArguments(Fold.MH_str, 1, Fold.MH_comb2);
+ assertEquals(Fold.MT_folded3, fold.type());
+ assertEquals(1, (int) fold.invoke(true, true, 1));
+ assertEquals(-1, (int) fold.invoke(true, false, -1));
+ }
+
+ @Test
+ public static void testFoldArgumentsExample() throws Throwable {
+ // test the JavaDoc foldArguments-with-pos example
+ StringWriter swr = new StringWriter();
+ MethodHandle trace = LOOKUP.findVirtual(StringWriter.class, "write", methodType(void.class, String.class)).bindTo(swr);
+ MethodHandle cat = LOOKUP.findVirtual(String.class, "concat", methodType(String.class, String.class));
+ assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
+ MethodHandle catTrace = MethodHandles.foldArguments(cat, 1, trace);
+ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
+ assertEquals("jum", swr.toString());
+ }
+
+ @Test
+ public static void testAsSpreader() throws Throwable {
+ MethodHandle spreader = SpreadCollect.MH_forSpreading.asSpreader(1, int[].class, 3);
+ assertEquals(SpreadCollect.MT_spreader, spreader.type());
+ assertEquals("A456B", (String) spreader.invoke("A", new int[]{4, 5, 6}, "B"));
+ }
+
+ @Test
+ public static void testAsSpreaderExample() throws Throwable {
+ // test the JavaDoc asSpreader-with-pos example
+ MethodHandle compare = LOOKUP.findStatic(Objects.class, "compare", methodType(int.class, Object.class, Object.class, Comparator.class));
+ MethodHandle compare2FromArray = compare.asSpreader(0, Object[].class, 2);
+ Object[] ints = new Object[]{3, 9, 7, 7};
+ Comparator<Integer> cmp = (a, b) -> a - b;
+ assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 0, 2), cmp) < 0);
+ assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 1, 3), cmp) > 0);
+ assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 2, 4), cmp) == 0);
+ }
+
+ @Test
+ public static void testAsSpreaderIllegalPos() throws Throwable {
+ int[] illegalPos = {-7, 3, 19};
+ int caught = 0;
+ for (int p : illegalPos) {
+ try {
+ SpreadCollect.MH_forSpreading.asSpreader(p, Object[].class, 3);
+ } catch (IllegalArgumentException iae) {
+ assertEquals("bad spread position", iae.getMessage());
+ ++caught;
+ }
+ }
+ assertEquals(illegalPos.length, caught);
+ }
+
+ @Test
+ public static void testAsCollector() throws Throwable {
+ MethodHandle collector = SpreadCollect.MH_forCollecting.asCollector(1, int[].class, 1);
+ assertEquals(SpreadCollect.MT_collector1, collector.type());
+ assertEquals("A4B", (String) collector.invoke("A", 4, "B"));
+ collector = SpreadCollect.MH_forCollecting.asCollector(1, int[].class, 2);
+ assertEquals(SpreadCollect.MT_collector2, collector.type());
+ assertEquals("A45B", (String) collector.invoke("A", 4, 5, "B"));
+ collector = SpreadCollect.MH_forCollecting.asCollector(1, int[].class, 3);
+ assertEquals(SpreadCollect.MT_collector3, collector.type());
+ assertEquals("A456B", (String) collector.invoke("A", 4, 5, 6, "B"));
+ }
+
+ @Test
+ public static void testAsCollectorInvokeWithArguments() throws Throwable {
+ MethodHandle collector = SpreadCollect.MH_forCollecting.asCollector(1, int[].class, 1);
+ assertEquals(SpreadCollect.MT_collector1, collector.type());
+ assertEquals("A4B", (String) collector.invokeWithArguments("A", 4, "B"));
+ collector = SpreadCollect.MH_forCollecting.asCollector(1, int[].class, 2);
+ assertEquals(SpreadCollect.MT_collector2, collector.type());
+ assertEquals("A45B", (String) collector.invokeWithArguments("A", 4, 5, "B"));
+ collector = SpreadCollect.MH_forCollecting.asCollector(1, int[].class, 3);
+ assertEquals(SpreadCollect.MT_collector3, collector.type());
+ assertEquals("A456B", (String) collector.invokeWithArguments("A", 4, 5, 6, "B"));
+ }
+
+ @Test
+ public static void testAsCollectorLeading() throws Throwable {
+ MethodHandle collector = SpreadCollect.MH_forCollectingLeading.asCollector(0, int[].class, 1);
+ assertEquals(SpreadCollect.MT_collectorLeading1, collector.type());
+ assertEquals("7Q", (String) collector.invoke(7, "Q"));
+ collector = SpreadCollect.MH_forCollectingLeading.asCollector(0, int[].class, 2);
+ assertEquals(SpreadCollect.MT_collectorLeading2, collector.type());
+ assertEquals("78Q", (String) collector.invoke(7, 8, "Q"));
+ collector = SpreadCollect.MH_forCollectingLeading.asCollector(0, int[].class, 3);
+ assertEquals(SpreadCollect.MT_collectorLeading3, collector.type());
+ assertEquals("789Q", (String) collector.invoke(7, 8, 9, "Q"));
+ }
+
+ @Test
+ public static void testAsCollectorLeadingInvokeWithArguments() throws Throwable {
+ MethodHandle collector = SpreadCollect.MH_forCollectingLeading.asCollector(0, int[].class, 1);
+ assertEquals(SpreadCollect.MT_collectorLeading1, collector.type());
+ assertEquals("7Q", (String) collector.invokeWithArguments(7, "Q"));
+ collector = SpreadCollect.MH_forCollectingLeading.asCollector(0, int[].class, 2);
+ assertEquals(SpreadCollect.MT_collectorLeading2, collector.type());
+ assertEquals("78Q", (String) collector.invokeWithArguments(7, 8, "Q"));
+ collector = SpreadCollect.MH_forCollectingLeading.asCollector(0, int[].class, 3);
+ assertEquals(SpreadCollect.MT_collectorLeading3, collector.type());
+ assertEquals("789Q", (String) collector.invokeWithArguments(7, 8, 9, "Q"));
+ }
+
+ @Test
+ public static void testAsCollectorNone() throws Throwable {
+ MethodHandle collector = SpreadCollect.MH_forCollecting.asCollector(1, int[].class, 0);
+ assertEquals(SpreadCollect.MT_collector0, collector.type());
+ assertEquals("AB", (String) collector.invoke("A", "B"));
+ }
+
+ @Test
+ public static void testAsCollectorIllegalPos() throws Throwable {
+ int[] illegalPos = {-1, 17};
+ int caught = 0;
+ for (int p : illegalPos) {
+ try {
+ SpreadCollect.MH_forCollecting.asCollector(p, int[].class, 0);
+ } catch (IllegalArgumentException iae) {
+ assertEquals("bad collect position", iae.getMessage());
+ ++caught;
+ }
+ }
+ assertEquals(illegalPos.length, caught);
+ }
+
+ @Test
+ public static void testAsCollectorExample() throws Throwable {
+ // test the JavaDoc asCollector-with-pos example
+ StringWriter swr = new StringWriter();
+ MethodHandle swWrite = LOOKUP.
+ findVirtual(StringWriter.class, "write", methodType(void.class, char[].class, int.class, int.class)).
+ bindTo(swr);
+ MethodHandle swWrite4 = swWrite.asCollector(0, char[].class, 4);
+ swWrite4.invoke('A', 'B', 'C', 'D', 1, 2);
+ assertEquals("BC", swr.toString());
+ swWrite4.invoke('P', 'Q', 'R', 'S', 0, 4);
+ assertEquals("BCPQRS", swr.toString());
+ swWrite4.invoke('W', 'X', 'Y', 'Z', 3, 1);
+ assertEquals("BCPQRSZ", swr.toString());
+ }
+
+ @Test
+ public static void testFindSpecial() throws Throwable {
+ FindSpecial.C c = new FindSpecial.C();
+ assertEquals("I1.m", c.m());
+ MethodType t = MethodType.methodType(String.class);
+ MethodHandle ci1m = LOOKUP.findSpecial(FindSpecial.I1.class, "m", t, FindSpecial.C.class);
+ assertEquals("I1.m", (String) ci1m.invoke(c));
+ }
+
+ @Test
+ public static void testFindSpecialAbstract() throws Throwable {
+ FindSpecial.C c = new FindSpecial.C();
+ assertEquals("q", c.q());
+ MethodType t = MethodType.methodType(String.class);
+ boolean caught = false;
+ try {
+ MethodHandle ci3q = LOOKUP.findSpecial(FindSpecial.I3.class, "q", t, FindSpecial.C.class);
+ } catch (Throwable thrown) {
+ if (!(thrown instanceof IllegalAccessException) || !FindSpecial.ABSTRACT_ERROR.equals(thrown.getMessage())) {
+ throw new AssertionError(thrown.getMessage(), thrown);
+ }
+ caught = true;
+ }
+ assertTrue(caught);
+ }
+
+ @Test
+ public static void testFindClassCNFE() throws Throwable {
+ boolean caught = false;
+ try {
+ LOOKUP.findClass("does.not.Exist");
+ } catch (ClassNotFoundException cnfe) {
+ caught = true;
+ }
+ assertTrue(caught);
+ }
+
+ //
+ // Methods used to assemble tests.
+ //
+
+ static class Empty {
+
+ static void f() { }
+
+ static boolean pred() {
+ return false;
+ }
+
+ static final Class<Empty> EMPTY = Empty.class;
+
+ static final MethodType MT_f = methodType(void.class);
+ static final MethodType MT_pred = methodType(boolean.class);
+
+ static final MethodHandle MH_f;
+ static final MethodHandle MH_pred;
+
+ static {
+ try {
+ MH_f = LOOKUP.findStatic(EMPTY, "f", MT_f);
+ MH_pred = LOOKUP.findStatic(EMPTY, "pred", MT_pred);
+ } catch (Exception e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+ }
+
+ static class Fac {
+
+ static int zero(int k) {
+ return 0;
+ }
+
+ static int one(int k) {
+ return 1;
+ }
+
+ static boolean pred(int i, int acc, int k) {
+ return i < k;
+ }
+
+ static int inc(int i, int acc, int k) {
+ return i + 1;
+ }
+
+ static int mult(int i, int acc, int k) {
+ return i * acc;
+ }
+
+ static void dot(int i, int acc, int k) {
+ System.out.print('.');
+ }
+
+ static int fin(int i, int acc, int k) {
+ return acc;
+ }
+
+ static final Class<Fac> FAC = Fac.class;
+
+ static final MethodType MT_init = methodType(int.class, int.class);
+ static final MethodType MT_fn = methodType(int.class, int.class, int.class, int.class);
+ static final MethodType MT_dot = methodType(void.class, int.class, int.class, int.class);
+ static final MethodType MT_pred = methodType(boolean.class, int.class, int.class, int.class);
+
+ static final MethodHandle MH_zero;
+ static final MethodHandle MH_one;
+ static final MethodHandle MH_pred;
+ static final MethodHandle MH_inc;
+ static final MethodHandle MH_mult;
+ static final MethodHandle MH_dot;
+ static final MethodHandle MH_fin;
+
+ static final MethodType MT_fac = methodType(int.class, int.class);
+
+ static {
+ try {
+ MH_zero = LOOKUP.findStatic(FAC, "zero", MT_init);
+ MH_one = LOOKUP.findStatic(FAC, "one", MT_init);
+ MH_pred = LOOKUP.findStatic(FAC, "pred", MT_pred);
+ MH_inc = LOOKUP.findStatic(FAC, "inc", MT_fn);
+ MH_mult = LOOKUP.findStatic(FAC, "mult", MT_fn);
+ MH_dot = LOOKUP.findStatic(FAC, "dot", MT_dot);
+ MH_fin = LOOKUP.findStatic(FAC, "fin", MT_fn);
+ } catch (Exception e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ }
+
+ static class While {
+
+ static int zero(int limit) {
+ return 0;
+ }
+
+ static boolean pred(int i, int limit) {
+ return i < limit;
+ }
+
+ static int step(int i, int limit) {
+ return i + 1;
+ }
+
+ static String initString() {
+ return "a";
+ }
+
+ static boolean predString(String s) {
+ return s.length() != 1;
+ }
+
+ static String stepString(String s) {
+ return s + "a";
+ }
+
+ static List<String> zipInitZip(Iterator<String> a, Iterator<String> b) {
+ return new ArrayList<>();
+ }
+
+ static boolean zipPred(List<String> zip, Iterator<String> a, Iterator<String> b) {
+ return a.hasNext() && b.hasNext();
+ }
+
+ static List<String> zipStep(List<String> zip, Iterator<String> a, Iterator<String> b) {
+ zip.add(a.next());
+ zip.add(b.next());
+ return zip;
+ }
+
+ static final Class<While> WHILE = While.class;
+
+ static final MethodType MT_zero = methodType(int.class, int.class);
+ static final MethodType MT_pred = methodType(boolean.class, int.class, int.class);
+ static final MethodType MT_fn = methodType(int.class, int.class, int.class);
+ static final MethodType MT_initString = methodType(String.class);
+ static final MethodType MT_predString = methodType(boolean.class, String.class);
+ static final MethodType MT_stepString = methodType(String.class, String.class);
+ static final MethodType MT_zipInitZip = methodType(List.class, Iterator.class, Iterator.class);
+ static final MethodType MT_zipPred = methodType(boolean.class, List.class, Iterator.class, Iterator.class);
+ static final MethodType MT_zipStep = methodType(List.class, List.class, Iterator.class, Iterator.class);
+
+ static final MethodHandle MH_zero;
+ static final MethodHandle MH_pred;
+ static final MethodHandle MH_step;
+ static final MethodHandle MH_initString;
+ static final MethodHandle MH_predString;
+ static final MethodHandle MH_stepString;
+ static final MethodHandle MH_zipInitZip;
+ static final MethodHandle MH_zipPred;
+ static final MethodHandle MH_zipStep;
+
+ static final MethodType MT_while = methodType(int.class, int.class);
+ static final MethodType MT_string = methodType(String.class);
+ static final MethodType MT_zip = methodType(List.class, Iterator.class, Iterator.class);
+
+ static {
+ try {
+ MH_zero = LOOKUP.findStatic(WHILE, "zero", MT_zero);
+ MH_pred = LOOKUP.findStatic(WHILE, "pred", MT_pred);
+ MH_step = LOOKUP.findStatic(WHILE, "step", MT_fn);
+ MH_initString = LOOKUP.findStatic(WHILE, "initString", MT_initString);
+ MH_predString = LOOKUP.findStatic(WHILE, "predString", MT_predString);
+ MH_stepString = LOOKUP.findStatic(WHILE, "stepString", MT_stepString);
+ MH_zipInitZip = LOOKUP.findStatic(WHILE, "zipInitZip", MT_zipInitZip);
+ MH_zipPred = LOOKUP.findStatic(WHILE, "zipPred", MT_zipPred);
+ MH_zipStep = LOOKUP.findStatic(WHILE, "zipStep", MT_zipStep);
+ } catch (Exception e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ }
+
+ static class Counted {
+
+ static String start(String arg) {
+ return arg;
+ }
+
+ static String step(int counter, String v, String arg) {
+ return "na " + v;
+ }
+
+ static void stepUpdateArray(int counter, int[] a) {
+ ++a[0];
+ }
+
+ static void printHello(int counter) {
+ System.out.print("hello");
+ }
+
+ static final Class<Counted> COUNTED = Counted.class;
+
+ static final MethodType MT_start = methodType(String.class, String.class);
+ static final MethodType MT_step = methodType(String.class, int.class, String.class, String.class);
+ static final MethodType MT_stepUpdateArray = methodType(void.class, int.class, int[].class);
+ static final MethodType MT_printHello = methodType(void.class, int.class);
+
+ static final MethodHandle MH_13;
+ static final MethodHandle MH_m5;
+ static final MethodHandle MH_8;
+ static final MethodHandle MH_start;
+ static final MethodHandle MH_step;
+ static final MethodHandle MH_stepUpdateArray;
+ static final MethodHandle MH_printHello;
+
+ static final MethodType MT_counted = methodType(String.class, String.class);
+ static final MethodType MT_arrayCounted = methodType(void.class, int[].class);
+ static final MethodType MT_countedPrinting = methodType(void.class);
+
+ static {
+ try {
+ MH_13 = MethodHandles.constant(int.class, 13);
+ MH_m5 = MethodHandles.constant(int.class, -5);
+ MH_8 = MethodHandles.constant(int.class, 8);
+ MH_start = LOOKUP.findStatic(COUNTED, "start", MT_start);
+ MH_step = LOOKUP.findStatic(COUNTED, "step", MT_step);
+ MH_stepUpdateArray = LOOKUP.findStatic(COUNTED, "stepUpdateArray", MT_stepUpdateArray);
+ MH_printHello = LOOKUP.findStatic(COUNTED, "printHello", MT_printHello);
+ } catch (Exception e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ }
+
+ static class Iterate {
+
+ static Iterator<Integer> sumIterator(Integer[] a) {
+ return Arrays.asList(a).iterator();
+ }
+
+ static int sumInit(Integer[] a) {
+ return 0;
+ }
+
+ static int sumStep(int s, int e, Integer[] a) {
+ return s + e;
+ }
+
+ static List<String> reverseInit(List<String> l) {
+ return new ArrayList<>();
+ }
+
+ static List<String> reverseStep(String e, List<String> r, List<String> l) {
+ r.add(0, e);
+ return r;
+ }
+
+ static int lengthInit(List<Double> l) {
+ return 0;
+ }
+
+ static int lengthStep(Object o, int len, List<Double> l) {
+ return len + 1;
+ }
+
+ static List<String> mapInit(List<String> l) {
+ return new ArrayList<>();
+ }
+
+ static List<String> mapStep(String e, List<String> r, List<String> l) {
+ r.add(e.toUpperCase());
+ return r;
+ }
+
+ static void printStep(String s, List<String> l) {
+ System.out.print(s);
+ }
+
+ static final Class<Iterate> ITERATE = Iterate.class;
+
+ static final MethodType MT_sumIterator = methodType(Iterator.class, Integer[].class);
+
+ static final MethodType MT_sumInit = methodType(int.class, Integer[].class);
+ static final MethodType MT_reverseInit = methodType(List.class, List.class);
+ static final MethodType MT_lenghInit = methodType(int.class, List.class);
+ static final MethodType MT_mapInit = methodType(List.class, List.class);
+
+ static final MethodType MT_sumStep = methodType(int.class, int.class, int.class, Integer[].class);
+ static final MethodType MT_reverseStep = methodType(List.class, String.class, List.class, List.class);
+ static final MethodType MT_lengthStep = methodType(int.class, Object.class, int.class, List.class);
+ static final MethodType MT_mapStep = methodType(List.class, String.class, List.class, List.class);
+ static final MethodType MT_printStep = methodType(void.class, String.class, List.class);
+
+ static final MethodHandle MH_sumIterator;
+ static final MethodHandle MH_sumInit;
+ static final MethodHandle MH_sumStep;
+ static final MethodHandle MH_printStep;
+
+ static final MethodHandle MH_reverseInit;
+ static final MethodHandle MH_reverseStep;
+
+ static final MethodHandle MH_lengthInit;
+ static final MethodHandle MH_lengthStep;
+
+ static final MethodHandle MH_mapInit;
+ static final MethodHandle MH_mapStep;
+
+ static final MethodType MT_sum = methodType(int.class, Integer[].class);
+ static final MethodType MT_reverse = methodType(List.class, List.class);
+ static final MethodType MT_length = methodType(int.class, List.class);
+ static final MethodType MT_map = methodType(List.class, List.class);
+ static final MethodType MT_print = methodType(void.class, List.class);
+
+ static {
+ try {
+ MH_sumIterator = LOOKUP.findStatic(ITERATE, "sumIterator", MT_sumIterator);
+ MH_sumInit = LOOKUP.findStatic(ITERATE, "sumInit", MT_sumInit);
+ MH_sumStep = LOOKUP.findStatic(ITERATE, "sumStep", MT_sumStep);
+ MH_reverseInit = LOOKUP.findStatic(ITERATE, "reverseInit", MT_reverseInit);
+ MH_reverseStep = LOOKUP.findStatic(ITERATE, "reverseStep", MT_reverseStep);
+ MH_lengthInit = LOOKUP.findStatic(ITERATE, "lengthInit", MT_lenghInit);
+ MH_lengthStep = LOOKUP.findStatic(ITERATE, "lengthStep", MT_lengthStep);
+ MH_mapInit = LOOKUP.findStatic(ITERATE, "mapInit", MT_mapInit);
+ MH_mapStep = LOOKUP.findStatic(ITERATE, "mapStep", MT_mapStep);
+ MH_printStep = LOOKUP.findStatic(ITERATE, "printStep", MT_printStep);
+ } catch (Exception e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ }
+
+ static class TryFinally {
+
+ static String greet(String whom) {
+ return "Hello, " + whom;
+ }
+
+ static String exclaim(Throwable t, String r, String whom) {
+ return r + "!";
+ }
+
+ static void print(String what) {
+ System.out.print("Hello, " + what);
+ }
+
+ static void printMore(Throwable t, String what) {
+ System.out.println("!");
+ }
+
+ static String greetMore(String first, String second) {
+ return "Hello, " + first + " and " + second;
+ }
+
+ static String exclaimMore(Throwable t, String r, String first) {
+ return r + " (but " + first + " first)!";
+ }
+
+ static final Class<TryFinally> TRY_FINALLY = TryFinally.class;
+
+ static final MethodType MT_greet = methodType(String.class, String.class);
+ static final MethodType MT_exclaim = methodType(String.class, Throwable.class, String.class, String.class);
+ static final MethodType MT_print = methodType(void.class, String.class);
+ static final MethodType MT_printMore = methodType(void.class, Throwable.class, String.class);
+ static final MethodType MT_greetMore = methodType(String.class, String.class, String.class);
+ static final MethodType MT_exclaimMore = methodType(String.class, Throwable.class, String.class, String.class);
+
+ static final MethodHandle MH_greet;
+ static final MethodHandle MH_exclaim;
+ static final MethodHandle MH_print;
+ static final MethodHandle MH_printMore;
+ static final MethodHandle MH_greetMore;
+ static final MethodHandle MH_exclaimMore;
+
+ static final MethodType MT_hello = methodType(String.class, String.class);
+ static final MethodType MT_printHello = methodType(void.class, String.class);
+ static final MethodType MT_moreHello = methodType(String.class, String.class, String.class);
+
+ static {
+ try {
+ MH_greet = LOOKUP.findStatic(TRY_FINALLY, "greet", MT_greet);
+ MH_exclaim = LOOKUP.findStatic(TRY_FINALLY, "exclaim", MT_exclaim);
+ MH_print = LOOKUP.findStatic(TRY_FINALLY, "print", MT_print);
+ MH_printMore = LOOKUP.findStatic(TRY_FINALLY, "printMore", MT_printMore);
+ MH_greetMore = LOOKUP.findStatic(TRY_FINALLY, "greetMore", MT_greetMore);
+ MH_exclaimMore = LOOKUP.findStatic(TRY_FINALLY, "exclaimMore", MT_exclaimMore);
+ } catch (Exception e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ }
+
+ static class Fold {
+
+ static int adder(int a, int b, int c) {
+ return a + b + c;
+ }
+
+ static int adder1(int a, int b) {
+ return a + b;
+ }
+
+ static int multer(int x, int q, int r, int s) {
+ return x * q * r * s;
+ }
+
+ static int str(boolean b1, String s, boolean b2, int x) {
+ return b1 && s.equals(String.valueOf(b2)) ? x : -x;
+ }
+
+ static boolean comb(String s, boolean b2) {
+ return !s.equals(b2);
+ }
+
+ static String comb2(boolean b2, int x) {
+ int ib = b2 ? 1 : 0;
+ return ib == x ? "true" : "false";
+ }
+
+ static final Class<Fold> FOLD = Fold.class;
+
+ static final MethodType MT_adder = methodType(int.class, int.class, int.class, int.class);
+ static final MethodType MT_adder1 = methodType(int.class, int.class, int.class);
+ static final MethodType MT_multer = methodType(int.class, int.class, int.class, int.class, int.class);
+ static final MethodType MT_str = methodType(int.class, boolean.class, String.class, boolean.class, int.class);
+ static final MethodType MT_comb = methodType(boolean.class, String.class, boolean.class);
+ static final MethodType MT_comb2 = methodType(String.class, boolean.class, int.class);
+
+ static final MethodHandle MH_adder;
+ static final MethodHandle MH_adder1;
+ static final MethodHandle MH_multer;
+ static final MethodHandle MH_str;
+ static final MethodHandle MH_comb;
+ static final MethodHandle MH_comb2;
+
+ static final MethodType MT_folded1 = methodType(int.class, int.class, int.class, int.class);
+ static final MethodType MT_folded2 = methodType(int.class, String.class, boolean.class, int.class);
+ static final MethodType MT_folded3 = methodType(int.class, boolean.class, boolean.class, int.class);
+
+ static {
+ try {
+ MH_adder = LOOKUP.findStatic(FOLD, "adder", MT_adder);
+ MH_adder1 = LOOKUP.findStatic(FOLD, "adder1", MT_adder1);
+ MH_multer = LOOKUP.findStatic(FOLD, "multer", MT_multer);
+ MH_str = LOOKUP.findStatic(FOLD, "str", MT_str);
+ MH_comb = LOOKUP.findStatic(FOLD, "comb", MT_comb);
+ MH_comb2 = LOOKUP.findStatic(FOLD, "comb2", MT_comb2);
+ } catch (Exception e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+ }
+
+ static class SpreadCollect {
+
+ static String forSpreading(String s1, int i1, int i2, int i3, String s2) {
+ return s1 + i1 + i2 + i3 + s2;
+ }
+
+ static String forCollecting(String s1, int[] is, String s2) {
+ StringBuilder sb = new StringBuilder(s1);
+ for (int i : is) {
+ sb.append(i);
+ }
+ return sb.append(s2).toString();
+ }
+
+ static String forCollectingLeading(int[] is, String s) {
+ return forCollecting("", is, s);
+ }
+
+ static final Class<SpreadCollect> SPREAD_COLLECT = SpreadCollect.class;
+
+ static final MethodType MT_forSpreading = methodType(String.class, String.class, int.class, int.class, int.class, String.class);
+ static final MethodType MT_forCollecting = methodType(String.class, String.class, int[].class, String.class);
+ static final MethodType MT_forCollectingLeading = methodType(String.class, int[].class, String.class);
+
+ static final MethodHandle MH_forSpreading;
+ static final MethodHandle MH_forCollecting;
+ static final MethodHandle MH_forCollectingLeading;
+
+ static final MethodType MT_spreader = methodType(String.class, String.class, int[].class, String.class);
+ static final MethodType MT_collector0 = methodType(String.class, String.class, String.class);
+ static final MethodType MT_collector1 = methodType(String.class, String.class, int.class, String.class);
+ static final MethodType MT_collector2 = methodType(String.class, String.class, int.class, int.class, String.class);
+ static final MethodType MT_collector3 = methodType(String.class, String.class, int.class, int.class, int.class, String.class);
+ static final MethodType MT_collectorLeading1 = methodType(String.class, int.class, String.class);
+ static final MethodType MT_collectorLeading2 = methodType(String.class, int.class, int.class, String.class);
+ static final MethodType MT_collectorLeading3 = methodType(String.class, int.class, int.class, int.class, String.class);
+
+ static final String NONE_ERROR = "zero array length in MethodHandle.asCollector";
+
+ static {
+ try {
+ MH_forSpreading = LOOKUP.findStatic(SPREAD_COLLECT, "forSpreading", MT_forSpreading);
+ MH_forCollecting = LOOKUP.findStatic(SPREAD_COLLECT, "forCollecting", MT_forCollecting);
+ MH_forCollectingLeading = LOOKUP.findStatic(SPREAD_COLLECT, "forCollectingLeading", MT_forCollectingLeading);
+ } catch (Exception e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ }
+
+ static class FindSpecial {
+
+ interface I1 {
+ default String m() {
+ return "I1.m";
+ }
+ }
+
+ interface I2 {
+ default String m() {
+ return "I2.m";
+ }
+ }
+
+ interface I3 {
+ String q();
+ }
+
+ static class C implements I1, I2, I3 {
+ public String m() {
+ return I1.super.m();
+ }
+ public String q() {
+ return "q";
+ }
+ }
+
+ static final String ABSTRACT_ERROR = "no such method: test.java.lang.invoke.T8139885$FindSpecial$I3.q()String/invokeSpecial";
+
+ }
+
+ //
+ // Auxiliary methods.
+ //
+
+ static MethodHandle[] mha(MethodHandle... mhs) {
+ return mhs;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/findclass.security.policy Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,9 @@
+/*
+ * Security policy used by the FindClassSecurityManager test.
+ * Must allow file reads so that jtreg itself can run, and getting class loaders.
+ */
+
+grant {
+ permission java.io.FilePermission "*", "read";
+ permission java.lang.RuntimePermission "getClassLoader";
+};
--- a/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/* @test
* @bug 8081678
* @summary Tests for stream returning methods
- * @library ../../util/stream/bootlib
+ * @library ../../util/stream/bootlib/java.base
* @build java.util.stream.OpTestCase
* @run testng/othervm NetworkInterfaceStreamTest
* @run testng/othervm -Djava.net.preferIPv4Stack=true NetworkInterfaceStreamTest
--- a/jdk/test/java/nio/file/Files/StreamLinesTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/nio/file/Files/StreamLinesTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -23,7 +23,7 @@
/* @test
* @bug 8072773
- * @library /lib/testlibrary/ ../../../util/stream/bootlib
+ * @library /lib/testlibrary/ ../../../util/stream/bootlib/java.base
* @build java.util.stream.OpTestCase
* @build jdk.testlibrary.RandomFactory
* @run testng/othervm StreamLinesTest
--- a/jdk/test/java/security/PermissionCollection/PermissionCollectionStreamTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/security/PermissionCollection/PermissionCollectionStreamTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/* @test
* @bug 8081678
* @summary Tests for stream returning methods
- * @library ../../util/stream/bootlib
+ * @library ../../util/stream/bootlib/java.base
* @build java.util.stream.OpTestCase
* @run testng/othervm PermissionCollectionStreamTest
*/
--- a/jdk/test/java/time/tck/java/time/TCKClock_Tick.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/time/tck/java/time/TCKClock_Tick.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -160,6 +160,17 @@
}
//-----------------------------------------------------------------------
+ public void test_tickMillis_ZoneId() throws Exception {
+ Clock test = Clock.tickMillis(PARIS);
+ assertEquals(test.getZone(), PARIS);
+ assertEquals(test.instant().getNano() % 1000_000, 0);
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void test_tickMillis_ZoneId_nullZoneId() {
+ Clock.tickMillis(null);
+ }
+ //-----------------------------------------------------------------------
public void test_tickSeconds_ZoneId() throws Exception {
Clock test = Clock.tickSeconds(PARIS);
assertEquals(test.getZone(), PARIS);
--- a/jdk/test/java/time/tck/java/time/TCKDuration.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/time/tck/java/time/TCKDuration.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -521,6 +521,8 @@
{"PT-123456789S", -123456789, 0},
{"PT" + Long.MIN_VALUE + "S", Long.MIN_VALUE, 0},
+
+ {"PT0.1S", 0, 100000000},
{"PT1.1S", 1, 100000000},
{"PT1.12S", 1, 120000000},
{"PT1.123S", 1, 123000000},
@@ -531,6 +533,7 @@
{"PT1.12345678S", 1, 123456780},
{"PT1.123456789S", 1, 123456789},
+ {"PT-0.1S", -1, 1000000000 - 100000000},
{"PT-1.1S", -2, 1000000000 - 100000000},
{"PT-1.12S", -2, 1000000000 - 120000000},
{"PT-1.123S", -2, 1000000000 - 123000000},
@@ -544,6 +547,24 @@
{"PT" + Long.MAX_VALUE + ".123456789S", Long.MAX_VALUE, 123456789},
{"PT" + Long.MIN_VALUE + ".000000000S", Long.MIN_VALUE, 0},
+ {"PT12M", 12 * 60, 0},
+ {"PT12M0.35S", 12 * 60, 350000000},
+ {"PT12M1.35S", 12 * 60 + 1, 350000000},
+ {"PT12M-0.35S", 12 * 60 - 1, 1000000000 - 350000000},
+ {"PT12M-1.35S", 12 * 60 - 2, 1000000000 - 350000000},
+
+ {"PT12H", 12 * 3600, 0},
+ {"PT12H0.35S", 12 * 3600, 350000000},
+ {"PT12H1.35S", 12 * 3600 + 1, 350000000},
+ {"PT12H-0.35S", 12 * 3600 - 1, 1000000000 - 350000000},
+ {"PT12H-1.35S", 12 * 3600 - 2, 1000000000 - 350000000},
+
+ {"P12D", 12 * 24 * 3600, 0},
+ {"P12DT0.35S", 12 * 24 * 3600, 350000000},
+ {"P12DT1.35S", 12 * 24 * 3600 + 1, 350000000},
+ {"P12DT-0.35S", 12 * 24 * 3600 - 1, 1000000000 - 350000000},
+ {"P12DT-1.35S", 12 * 24 * 3600 - 2, 1000000000 - 350000000},
+
{"PT01S", 1, 0},
{"PT001S", 1, 0},
{"PT000S", 0, 0},
--- a/jdk/test/java/time/tck/java/time/TCKLocalDate.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/time/tck/java/time/TCKLocalDate.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -86,8 +86,6 @@
import static org.testng.Assert.assertSame;
import static org.testng.Assert.assertTrue;
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.DayOfWeek;
@@ -104,6 +102,7 @@
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.chrono.IsoChronology;
+import java.time.chrono.IsoEra;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
@@ -135,6 +134,7 @@
private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1);
private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
+ private static final ZoneOffset OFFSET_MTWO = ZoneOffset.ofHours(-2);
private static final ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris");
private static final ZoneId ZONE_GAZA = ZoneId.of("Asia/Gaza");
@@ -475,6 +475,48 @@
return date.withDayOfMonth(date.getMonth().length(isIsoLeap(date.getYear())));
}
+ //-----------------------------------------------------------------------
+ // ofInstant()
+ //-----------------------------------------------------------------------
+ @DataProvider(name="instantFactory")
+ Object[][] data_instantFactory() {
+ return new Object[][] {
+ {Instant.ofEpochSecond(86400 + 3600 + 120 + 4, 500), ZONE_PARIS, LocalDate.of(1970, 1, 2)},
+ {Instant.ofEpochSecond(86400 + 3600 + 120 + 4, 500), OFFSET_MTWO, LocalDate.of(1970, 1, 1)},
+ {Instant.ofEpochSecond(-86400 + 4, 500), OFFSET_PTWO, LocalDate.of(1969, 12, 31)},
+ {OffsetDateTime.of(LocalDateTime.of(Year.MIN_VALUE, 1, 1, 0, 0), ZoneOffset.UTC).toInstant(),
+ ZoneOffset.UTC, LocalDate.MIN},
+ {OffsetDateTime.of(LocalDateTime.of(Year.MAX_VALUE, 12, 31, 23, 59, 59, 999_999_999), ZoneOffset.UTC).toInstant(),
+ ZoneOffset.UTC, LocalDate.MAX},
+ };
+ }
+
+ @Test(dataProvider="instantFactory")
+ public void factory_ofInstant(Instant instant, ZoneId zone, LocalDate expected) {
+ LocalDate test = LocalDate.ofInstant(instant, zone);
+ assertEquals(test, expected);
+ }
+
+ @Test(expectedExceptions=DateTimeException.class)
+ public void factory_ofInstant_instantTooBig() {
+ LocalDate.ofInstant(Instant.MAX, OFFSET_PONE);
+ }
+
+ @Test(expectedExceptions=DateTimeException.class)
+ public void factory_ofInstant_instantTooSmall() {
+ LocalDate.ofInstant(Instant.MIN, OFFSET_PONE);
+ }
+
+ @Test(expectedExceptions=NullPointerException.class)
+ public void factory_ofInstant_nullInstant() {
+ LocalDate.ofInstant((Instant) null, ZONE_GAZA);
+ }
+
+ @Test(expectedExceptions=NullPointerException.class)
+ public void factory_ofInstant_nullZone() {
+ LocalDate.ofInstant(Instant.EPOCH, (ZoneId) null);
+ }
+
//-----------------------------------------------------------------------
// ofEpochDay()
//-----------------------------------------------------------------------
@@ -2285,4 +2327,13 @@
return LocalDate.of(year, month, day);
}
+ //-----------------------------------------------------------------
+ // getEra()
+ // ----------------------------------------------------------------
+ @Test
+ public void test_getEra() {
+ IsoEra isoEra = LocalDate.MAX.getEra();
+ assertSame(isoEra,IsoEra.CE);
+ assertSame(LocalDate.MIN.getEra(),IsoEra.BCE);
+ }
}
--- a/jdk/test/java/time/tck/java/time/TCKLocalTime.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/time/tck/java/time/TCKLocalTime.java Wed Jul 05 21:02:29 2017 +0200
@@ -102,6 +102,7 @@
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.Period;
+import java.time.Year;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
@@ -137,6 +138,7 @@
public class TCKLocalTime extends AbstractDateTimeTest {
private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
+ private static final ZoneOffset OFFSET_MTWO = ZoneOffset.ofHours(-2);
private static final ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris");
private LocalTime TEST_12_30_40_987654321;
@@ -420,6 +422,38 @@
LocalTime.of(0, 0, 0, 1000000000);
}
+ //-----------------------------------------------------------------------
+ // ofInstant()
+ //-----------------------------------------------------------------------
+ @DataProvider(name="instantFactory")
+ Object[][] data_instantFactory() {
+ return new Object[][] {
+ {Instant.ofEpochSecond(86400 + 3600 + 120 + 4, 500), ZONE_PARIS, LocalTime.of(2, 2, 4, 500)},
+ {Instant.ofEpochSecond(86400 + 3600 + 120 + 4, 500), OFFSET_MTWO, LocalTime.of(23, 2, 4, 500)},
+ {Instant.ofEpochSecond(-86400 + 4, 500), OFFSET_PTWO, LocalTime.of(2, 0, 4, 500)},
+ {OffsetDateTime.of(LocalDateTime.of(Year.MIN_VALUE, 1, 1, 0, 0), ZoneOffset.UTC).toInstant(),
+ ZoneOffset.UTC, LocalTime.MIN},
+ {OffsetDateTime.of(LocalDateTime.of(Year.MAX_VALUE, 12, 31, 23, 59, 59, 999_999_999), ZoneOffset.UTC).toInstant(),
+ ZoneOffset.UTC, LocalTime.MAX},
+ };
+ }
+
+ @Test(dataProvider="instantFactory")
+ public void factory_ofInstant(Instant instant, ZoneId zone, LocalTime expected) {
+ LocalTime test = LocalTime.ofInstant(instant, zone);
+ assertEquals(test, expected);
+ }
+
+ @Test(expectedExceptions=NullPointerException.class)
+ public void factory_ofInstant_nullInstant() {
+ LocalTime.ofInstant((Instant) null, ZONE_PARIS);
+ }
+
+ @Test(expectedExceptions=NullPointerException.class)
+ public void factory_ofInstant_nullZone() {
+ LocalTime.ofInstant(Instant.EPOCH, (ZoneId) null);
+ }
+
//-----------------------------------------------------------------------
// ofSecondOfDay(long)
//-----------------------------------------------------------------------
--- a/jdk/test/java/util/Arrays/ArraysEqCmpTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/util/Arrays/ArraysEqCmpTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8033148
+ * @bug 8033148 8141409
* @summary tests for array equals and compare
* @run testng ArraysEqCmpTest
*/
@@ -312,6 +312,8 @@
return Integer.compare(b, a);
};
+ final MethodHandle eqc;
+ final MethodHandle eqcr;
final MethodHandle cmpc;
final MethodHandle cmpcr;
final MethodHandle mismatchc;
@@ -327,6 +329,8 @@
int.class, Object[].class, int.class, int.class,
Object[].class, int.class, int.class, Comparator.class);
+ eqc = l.findStatic(Arrays.class, "equals", cmpt.changeReturnType(boolean.class));
+ eqcr = l.findStatic(Arrays.class, "equals", cmprt.changeReturnType(boolean.class));
cmpc = l.findStatic(Arrays.class, "compare", cmpt);
cmpcr = l.findStatic(Arrays.class, "compare", cmprt);
mismatchc = l.findStatic(Arrays.class, "mismatch", cmpt);
@@ -338,6 +342,33 @@
}
@Override
+ boolean equals(Object a, Object b) {
+ try {
+ return (boolean) eqc.invoke(a, b, c);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ @Override
+ boolean equals(Object a, int aFromIndex, int aToIndex,
+ Object b, int bFromIndex, int bToIndex) {
+ try {
+ return (boolean) eqcr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex, c);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ @Override
int compare(Object a, Object b) {
try {
return (int) cmpc.invoke(a, b, c);
@@ -1002,10 +1033,12 @@
continue;
if (o3 == null) {
+ testNPE(() -> Arrays.equals(o1, o2, o3));
testNPE(() -> Arrays.compare(o1, o2, o3));
testNPE(() -> Arrays.mismatch(o1, o2, o3));
}
+ testNPE(() -> Arrays.equals(o1, 0, 0, o2, 0, 0, o3));
testNPE(() -> Arrays.compare(o1, 0, 0, o2, 0, 0, o3));
testNPE(() -> Arrays.mismatch(o1, 0, 0, o2, 0, 0, o3));
}
--- a/jdk/test/java/util/Arrays/TimSortStackSize2.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/util/Arrays/TimSortStackSize2.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @bug 8072909
- * @library /lib/testlibrary /../../test/lib
+ * @library /lib/testlibrary /test/lib
* @build jdk.testlibrary.*
* @build TimSortStackSize2
* @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/jdk/test/java/util/Objects/CheckIndex.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/util/Objects/CheckIndex.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @summary IndexOutOfBoundsException check index tests
* @run testng CheckIndex
- * @bug 8135248
+ * @bug 8135248 8142493
*/
import org.testng.annotations.DataProvider;
@@ -54,6 +54,15 @@
};
}
+ static BiFunction<Integer, Integer, AssertingOutOfBoundsException> assertingOutOfBoundsReturnNull(
+ int expFromIndex, int expToIndexOrSizeOrLength) {
+ return (fromIndex, toIndexOrSizeorLength) -> {
+ assertEquals(fromIndex, Integer.valueOf(expFromIndex));
+ assertEquals(toIndexOrSizeorLength, Integer.valueOf(expToIndexOrSizeOrLength));
+ return null;
+ };
+ }
+
static final int[] VALUES = {0, 1, Integer.MAX_VALUE - 1, Integer.MAX_VALUE, -1, Integer.MIN_VALUE + 1, Integer.MIN_VALUE};
@DataProvider
@@ -95,6 +104,8 @@
check.accept(AssertingOutOfBoundsException.class,
() -> Objects.checkIndex(index, length, assertingOutOfBounds(index, length)));
check.accept(IndexOutOfBoundsException.class,
+ () -> Objects.checkIndex(index, length, assertingOutOfBoundsReturnNull(index, length)));
+ check.accept(IndexOutOfBoundsException.class,
() -> Objects.checkIndex(index, length, null));
check.accept(IndexOutOfBoundsException.class,
() -> Objects.checkIndex(index, length));
@@ -140,6 +151,8 @@
check.accept(AssertingOutOfBoundsException.class,
() -> Objects.checkFromToIndex(fromIndex, toIndex, length, assertingOutOfBounds(fromIndex, toIndex)));
check.accept(IndexOutOfBoundsException.class,
+ () -> Objects.checkFromToIndex(fromIndex, toIndex, length, assertingOutOfBoundsReturnNull(fromIndex, toIndex)));
+ check.accept(IndexOutOfBoundsException.class,
() -> Objects.checkFromToIndex(fromIndex, toIndex, length, null));
check.accept(IndexOutOfBoundsException.class,
() -> Objects.checkFromToIndex(fromIndex, toIndex, length));
@@ -192,6 +205,8 @@
check.accept(AssertingOutOfBoundsException.class,
() -> Objects.checkFromIndexSize(fromIndex, size, length, assertingOutOfBounds(fromIndex, size)));
check.accept(IndexOutOfBoundsException.class,
+ () -> Objects.checkFromIndexSize(fromIndex, size, length, assertingOutOfBoundsReturnNull(fromIndex, size)));
+ check.accept(IndexOutOfBoundsException.class,
() -> Objects.checkFromIndexSize(fromIndex, size, length, null));
check.accept(IndexOutOfBoundsException.class,
() -> Objects.checkFromIndexSize(fromIndex, size, length));
--- a/jdk/test/java/util/Scanner/ScannerStreamTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/util/Scanner/ScannerStreamTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -46,7 +46,7 @@
* @test
* @bug 8072722
* @summary Tests of stream support in java.util.Scanner
- * @library ../stream/bootlib
+ * @library ../stream/bootlib/java.base
* @build java.util.stream.OpTestCase
* @run testng/othervm ScannerStreamTest
*/
--- a/jdk/test/java/util/logging/LoggerSubclass.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/util/logging/LoggerSubclass.java Wed Jul 05 21:02:29 2017 +0200
@@ -92,7 +92,7 @@
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {new LoggerSubclass().instanceMain(args);}
- catch (Throwable e) {throw e.getCause();}}
+ catch (Throwable e) {throw e.getCause() == null ? e : e.getCause();}}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
--- a/jdk/test/java/util/regex/PatternStreamTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/util/regex/PatternStreamTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,7 +25,7 @@
* @test
* @bug 8016846 8024341 8071479
* @summary Unit tests stream and lambda-based methods on Pattern and Matcher
- * @library ../stream/bootlib
+ * @library ../stream/bootlib/java.base
* @build java.util.stream.OpTestCase
* @run testng/othervm PatternStreamTest
*/
--- a/jdk/test/java/util/stream/bootlib/TEST.properties Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/util/stream/bootlib/TEST.properties Wed Jul 05 21:02:29 2017 +0200
@@ -1,3 +1,3 @@
# This file identifies root(s) of the test-ng hierarchy.
-bootclasspath.dirs = .
+bootclasspath.dirs = java.base
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/CollectorOps.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.Assert;
+
+import java.util.Spliterator;
+import java.util.function.IntFunction;
+
+/** Test helper class for java.util.stream test framework */
+public final class CollectorOps {
+ private CollectorOps() { }
+
+ public static <E_IN> StatefulTestOp<E_IN> collector() {
+ return new StatefulCollector<>(0, StreamShape.REFERENCE);
+ }
+
+ /* Utility classes for collecting output of intermediate pipeline stages */
+ public static class StatefulCollector<E_IN> implements StatefulTestOp<E_IN> {
+ private final int opFlags;
+ private final StreamShape inputShape;
+
+ public StatefulCollector(int opFlags, StreamShape inputShape) {
+ this.opFlags = opFlags;
+ this.inputShape = inputShape;
+ }
+
+ @Override
+ public StreamShape inputShape() {
+ return inputShape;
+ }
+
+ @Override
+ public StreamShape outputShape() {
+ return inputShape;
+ }
+
+ @Override
+ public int opGetFlags() {
+ return opFlags;
+ }
+
+ @Override
+ public Sink<E_IN> opWrapSink(int flags, boolean parallel, Sink<E_IN> sink) {
+ return sink;
+ }
+
+ @Override
+ public <P_IN> Node<E_IN> opEvaluateParallel(PipelineHelper<E_IN> helper,
+ Spliterator<P_IN> spliterator,
+ IntFunction<E_IN[]> generator) {
+ return helper.evaluate(spliterator, false, generator);
+ }
+ }
+
+ public static class TestParallelSizedOp<T> extends StatefulCollector<T> {
+ public TestParallelSizedOp() {
+ this(StreamShape.REFERENCE);
+ }
+
+ protected TestParallelSizedOp(StreamShape shape) {
+ super(0, shape);
+ }
+
+ @Override
+ public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+ Spliterator<P_IN> spliterator,
+ IntFunction<T[]> generator) {
+ int flags = helper.getStreamAndOpFlags();
+
+ Assert.assertTrue(StreamOpFlag.SIZED.isKnown(flags));
+ return super.opEvaluateParallel(helper, spliterator, generator);
+ }
+
+ public static class OfInt extends TestParallelSizedOp<Integer> {
+ public OfInt() {
+ super(StreamShape.INT_VALUE);
+ }
+ }
+
+ public static class OfLong extends TestParallelSizedOp<Long> {
+ public OfLong() {
+ super(StreamShape.LONG_VALUE);
+ }
+ }
+
+ public static class OfDouble extends TestParallelSizedOp<Double> {
+ public OfDouble() {
+ super(StreamShape.DOUBLE_VALUE);
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/DefaultMethodStreams.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,984 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Comparator;
+import java.util.DoubleSummaryStatistics;
+import java.util.IntSummaryStatistics;
+import java.util.Iterator;
+import java.util.LongSummaryStatistics;
+import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+import java.util.PrimitiveIterator;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleFunction;
+import java.util.function.DoublePredicate;
+import java.util.function.DoubleToIntFunction;
+import java.util.function.DoubleToLongFunction;
+import java.util.function.DoubleUnaryOperator;
+import java.util.function.Function;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.IntPredicate;
+import java.util.function.IntToDoubleFunction;
+import java.util.function.IntToLongFunction;
+import java.util.function.IntUnaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongConsumer;
+import java.util.function.LongFunction;
+import java.util.function.LongPredicate;
+import java.util.function.LongToDoubleFunction;
+import java.util.function.LongToIntFunction;
+import java.util.function.LongUnaryOperator;
+import java.util.function.ObjDoubleConsumer;
+import java.util.function.ObjIntConsumer;
+import java.util.function.ObjLongConsumer;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.ToDoubleFunction;
+
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+import static java.util.stream.Collectors.*;
+
+public final class DefaultMethodStreams {
+
+ static {
+ // Verify that default methods are not overridden
+ verify(DefaultMethodRefStream.class);
+ verify(DefaultMethodIntStream.class);
+ verify(DefaultMethodLongStream.class);
+ verify(DefaultMethodDoubleStream.class);
+ }
+
+ static void verify(Class<?> del) {
+ // Find the stream interface
+ Class<?> s = Stream.of(del.getInterfaces())
+ .filter(c -> BaseStream.class.isAssignableFrom(c))
+ .findFirst().get();
+
+ // Get all default methods on the stream class
+ Set<String> dms = Stream.of(s.getMethods())
+ .filter(m -> !Modifier.isStatic(m.getModifiers()))
+ .filter(m -> !m.isBridge())
+ .filter(Method::isDefault)
+ .map(Method::getName)
+ .collect(toSet());
+
+ // Get all methods on the delegating class
+ Set<String> ims = Stream.of(del.getMethods())
+ .filter(m -> !Modifier.isStatic(m.getModifiers()))
+ .filter(m -> m.getDeclaringClass() == del)
+ .map(Method::getName)
+ .collect(toSet());
+
+ if (ims.stream().anyMatch(dms::contains)) {
+ throw new AssertionError(String.format("%s overrides default methods of %s\n", del, s));
+ }
+ }
+
+ /**
+ * Creates a stream that for the next operation either delegates to
+ * a default method on {@link Stream}, if present for that operation,
+ * otherwise delegates to an underlying stream.
+ *
+ * @param s the underlying stream to be delegated to for non-default
+ * methods.
+ * @param <T> the type of the stream elements
+ * @return the delegating stream
+ */
+ public static <T> Stream<T> delegateTo(Stream<T> s) {
+ return new DefaultMethodRefStream<>(s);
+ }
+
+ /**
+ * Creates a stream that for the next operation either delegates to
+ * a default method on {@link IntStream}, if present for that operation,
+ * otherwise delegates to an underlying stream.
+ *
+ * @param s the underlying stream to be delegated to for non-default
+ * methods.
+ * @return the delegating stream
+ */
+ public static IntStream delegateTo(IntStream s) {
+ return new DefaultMethodIntStream(s);
+ }
+
+ /**
+ * Creates a stream that for the next operation either delegates to
+ * a default method on {@link LongStream}, if present for that operation,
+ * otherwise delegates to an underlying stream.
+ *
+ * @param s the underlying stream to be delegated to for non-default
+ * methods.
+ * @return the delegating stream
+ */
+ public static LongStream delegateTo(LongStream s) {
+ return new DefaultMethodLongStream(s);
+ }
+
+ /**
+ * Creates a stream that for the next operation either delegates to
+ * a default method on {@link DoubleStream}, if present for that operation,
+ * otherwise delegates to an underlying stream.
+ *
+ * @param s the underlying stream to be delegated to for non-default
+ * methods.
+ * @return the delegating stream
+ */
+ public static DoubleStream delegateTo(DoubleStream s) {
+ return new DefaultMethodDoubleStream(s);
+ }
+
+ /**
+ * A stream that delegates the next operation to a default method, if
+ * present, or to the same operation of an underlying stream.
+ *
+ * @param <T> the type of the stream elements
+ */
+ static final class DefaultMethodRefStream<T> implements Stream<T> {
+ final Stream<T> s;
+
+ DefaultMethodRefStream(Stream<T> s) {
+ this.s = s;
+ }
+
+
+ // Delegating non-default methods
+
+ @Override
+ public Stream<T> filter(Predicate<? super T> predicate) {
+ return s.filter(predicate);
+ }
+
+ @Override
+ public <R> Stream<R> map(Function<? super T, ? extends R> mapper) {
+ return s.map(mapper);
+ }
+
+ @Override
+ public IntStream mapToInt(ToIntFunction<? super T> mapper) {
+ return s.mapToInt(mapper);
+ }
+
+ @Override
+ public LongStream mapToLong(ToLongFunction<? super T> mapper) {
+ return s.mapToLong(mapper);
+ }
+
+ @Override
+ public DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper) {
+ return s.mapToDouble(mapper);
+ }
+
+ @Override
+ public <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper) {
+ return s.flatMap(mapper);
+ }
+
+ @Override
+ public IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper) {
+ return s.flatMapToInt(mapper);
+ }
+
+ @Override
+ public LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper) {
+ return s.flatMapToLong(mapper);
+ }
+
+ @Override
+ public DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper) {
+ return s.flatMapToDouble(mapper);
+ }
+
+ @Override
+ public Stream<T> distinct() {
+ return s.distinct();
+ }
+
+ @Override
+ public Stream<T> sorted() {
+ return s.sorted();
+ }
+
+ @Override
+ public Stream<T> sorted(Comparator<? super T> comparator) {
+ return s.sorted(comparator);
+ }
+
+ @Override
+ public Stream<T> peek(Consumer<? super T> action) {
+ return s.peek(action);
+ }
+
+ @Override
+ public Stream<T> limit(long maxSize) {
+ return s.limit(maxSize);
+ }
+
+ @Override
+ public Stream<T> skip(long n) {
+ return s.skip(n);
+ }
+
+ @Override
+ public void forEach(Consumer<? super T> action) {
+ s.forEach(action);
+ }
+
+ @Override
+ public void forEachOrdered(Consumer<? super T> action) {
+ s.forEachOrdered(action);
+ }
+
+ @Override
+ public Object[] toArray() {
+ return s.toArray();
+ }
+
+ @Override
+ public <A> A[] toArray(IntFunction<A[]> generator) {
+ return s.toArray(generator);
+ }
+
+ @Override
+ public T reduce(T identity, BinaryOperator<T> accumulator) {
+ return s.reduce(identity, accumulator);
+ }
+
+ @Override
+ public Optional<T> reduce(BinaryOperator<T> accumulator) {
+ return s.reduce(accumulator);
+ }
+
+ @Override
+ public <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner) {
+ return s.reduce(identity, accumulator, combiner);
+ }
+
+ @Override
+ public <R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner) {
+ return s.collect(supplier, accumulator, combiner);
+ }
+
+ @Override
+ public <R, A> R collect(Collector<? super T, A, R> collector) {
+ return s.collect(collector);
+ }
+
+ @Override
+ public Optional<T> min(Comparator<? super T> comparator) {
+ return s.min(comparator);
+ }
+
+ @Override
+ public Optional<T> max(Comparator<? super T> comparator) {
+ return s.max(comparator);
+ }
+
+ @Override
+ public long count() {
+ return s.count();
+ }
+
+ @Override
+ public boolean anyMatch(Predicate<? super T> predicate) {
+ return s.anyMatch(predicate);
+ }
+
+ @Override
+ public boolean allMatch(Predicate<? super T> predicate) {
+ return s.allMatch(predicate);
+ }
+
+ @Override
+ public boolean noneMatch(Predicate<? super T> predicate) {
+ return s.noneMatch(predicate);
+ }
+
+ @Override
+ public Optional<T> findFirst() {
+ return s.findFirst();
+ }
+
+ @Override
+ public Optional<T> findAny() {
+ return s.findAny();
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return s.iterator();
+ }
+
+ @Override
+ public Spliterator<T> spliterator() {
+ return s.spliterator();
+ }
+
+ @Override
+ public boolean isParallel() {
+ return s.isParallel();
+ }
+
+ @Override
+ public Stream<T> sequential() {
+ return s.sequential();
+ }
+
+ @Override
+ public Stream<T> parallel() {
+ return s.parallel();
+ }
+
+ @Override
+ public Stream<T> unordered() {
+ return s.unordered();
+ }
+
+ @Override
+ public Stream<T> onClose(Runnable closeHandler) {
+ return s.onClose(closeHandler);
+ }
+
+ @Override
+ public void close() {
+ s.close();
+ }
+ }
+
+ static final class DefaultMethodIntStream implements IntStream {
+ final IntStream s;
+
+ public DefaultMethodIntStream(IntStream s) {
+ this.s = s;
+ }
+
+
+ // Delegating non-default methods
+
+ @Override
+ public IntStream filter(IntPredicate predicate) {
+ return s.filter(predicate);
+ }
+
+ @Override
+ public IntStream map(IntUnaryOperator mapper) {
+ return s.map(mapper);
+ }
+
+ @Override
+ public <U> Stream<U> mapToObj(IntFunction<? extends U> mapper) {
+ return s.mapToObj(mapper);
+ }
+
+ @Override
+ public LongStream mapToLong(IntToLongFunction mapper) {
+ return s.mapToLong(mapper);
+ }
+
+ @Override
+ public DoubleStream mapToDouble(IntToDoubleFunction mapper) {
+ return s.mapToDouble(mapper);
+ }
+
+ @Override
+ public IntStream flatMap(IntFunction<? extends IntStream> mapper) {
+ return s.flatMap(mapper);
+ }
+
+ @Override
+ public IntStream distinct() {
+ return s.distinct();
+ }
+
+ @Override
+ public IntStream sorted() {
+ return s.sorted();
+ }
+
+ @Override
+ public IntStream peek(IntConsumer action) {
+ return s.peek(action);
+ }
+
+ @Override
+ public IntStream limit(long maxSize) {
+ return s.limit(maxSize);
+ }
+
+ @Override
+ public IntStream skip(long n) {
+ return s.skip(n);
+ }
+
+ @Override
+ public void forEach(IntConsumer action) {
+ s.forEach(action);
+ }
+
+ @Override
+ public void forEachOrdered(IntConsumer action) {
+ s.forEachOrdered(action);
+ }
+
+ @Override
+ public int[] toArray() {
+ return s.toArray();
+ }
+
+ @Override
+ public int reduce(int identity, IntBinaryOperator op) {
+ return s.reduce(identity, op);
+ }
+
+ @Override
+ public OptionalInt reduce(IntBinaryOperator op) {
+ return s.reduce(op);
+ }
+
+ @Override
+ public <R> R collect(Supplier<R> supplier, ObjIntConsumer<R> accumulator, BiConsumer<R, R> combiner) {
+ return s.collect(supplier, accumulator, combiner);
+ }
+
+ @Override
+ public int sum() {
+ return s.sum();
+ }
+
+ @Override
+ public OptionalInt min() {
+ return s.min();
+ }
+
+ @Override
+ public OptionalInt max() {
+ return s.max();
+ }
+
+ @Override
+ public long count() {
+ return s.count();
+ }
+
+ @Override
+ public OptionalDouble average() {
+ return s.average();
+ }
+
+ @Override
+ public IntSummaryStatistics summaryStatistics() {
+ return s.summaryStatistics();
+ }
+
+ @Override
+ public boolean anyMatch(IntPredicate predicate) {
+ return s.anyMatch(predicate);
+ }
+
+ @Override
+ public boolean allMatch(IntPredicate predicate) {
+ return s.allMatch(predicate);
+ }
+
+ @Override
+ public boolean noneMatch(IntPredicate predicate) {
+ return s.noneMatch(predicate);
+ }
+
+ @Override
+ public OptionalInt findFirst() {
+ return s.findFirst();
+ }
+
+ @Override
+ public OptionalInt findAny() {
+ return s.findAny();
+ }
+
+ @Override
+ public LongStream asLongStream() {
+ return s.asLongStream();
+ }
+
+ @Override
+ public DoubleStream asDoubleStream() {
+ return s.asDoubleStream();
+ }
+
+ @Override
+ public Stream<Integer> boxed() {
+ return s.boxed();
+ }
+
+ @Override
+ public IntStream sequential() {
+ return s.sequential();
+ }
+
+ @Override
+ public IntStream parallel() {
+ return s.parallel();
+ }
+
+ @Override
+ public PrimitiveIterator.OfInt iterator() {
+ return s.iterator();
+ }
+
+ @Override
+ public Spliterator.OfInt spliterator() {
+ return s.spliterator();
+ }
+
+ @Override
+ public boolean isParallel() {
+ return s.isParallel();
+ }
+
+ @Override
+ public IntStream unordered() {
+ return s.unordered();
+ }
+
+ @Override
+ public IntStream onClose(Runnable closeHandler) {
+ return s.onClose(closeHandler);
+ }
+
+ @Override
+ public void close() {
+ s.close();
+ }
+ }
+
+ static final class DefaultMethodLongStream implements LongStream {
+ final LongStream s;
+
+ public DefaultMethodLongStream(LongStream s) {
+ this.s = s;
+ }
+
+
+ // Delegating non-default methods
+
+ @Override
+ public void forEach(LongConsumer action) {
+ s.forEach(action);
+ }
+
+ @Override
+ public LongStream filter(LongPredicate predicate) {
+ return s.filter(predicate);
+ }
+
+ @Override
+ public LongStream map(LongUnaryOperator mapper) {
+ return s.map(mapper);
+ }
+
+ @Override
+ public <U> Stream<U> mapToObj(LongFunction<? extends U> mapper) {
+ return s.mapToObj(mapper);
+ }
+
+ @Override
+ public IntStream mapToInt(LongToIntFunction mapper) {
+ return s.mapToInt(mapper);
+ }
+
+ @Override
+ public DoubleStream mapToDouble(LongToDoubleFunction mapper) {
+ return s.mapToDouble(mapper);
+ }
+
+ @Override
+ public LongStream flatMap(LongFunction<? extends LongStream> mapper) {
+ return s.flatMap(mapper);
+ }
+
+ @Override
+ public LongStream distinct() {
+ return s.distinct();
+ }
+
+ @Override
+ public LongStream sorted() {
+ return s.sorted();
+ }
+
+ @Override
+ public LongStream peek(LongConsumer action) {
+ return s.peek(action);
+ }
+
+ @Override
+ public LongStream limit(long maxSize) {
+ return s.limit(maxSize);
+ }
+
+ @Override
+ public LongStream skip(long n) {
+ return s.skip(n);
+ }
+
+ @Override
+ public void forEachOrdered(LongConsumer action) {
+ s.forEachOrdered(action);
+ }
+
+ @Override
+ public long[] toArray() {
+ return s.toArray();
+ }
+
+ @Override
+ public long reduce(long identity, LongBinaryOperator op) {
+ return s.reduce(identity, op);
+ }
+
+ @Override
+ public OptionalLong reduce(LongBinaryOperator op) {
+ return s.reduce(op);
+ }
+
+ @Override
+ public <R> R collect(Supplier<R> supplier, ObjLongConsumer<R> accumulator, BiConsumer<R, R> combiner) {
+ return s.collect(supplier, accumulator, combiner);
+ }
+
+ @Override
+ public long sum() {
+ return s.sum();
+ }
+
+ @Override
+ public OptionalLong min() {
+ return s.min();
+ }
+
+ @Override
+ public OptionalLong max() {
+ return s.max();
+ }
+
+ @Override
+ public long count() {
+ return s.count();
+ }
+
+ @Override
+ public OptionalDouble average() {
+ return s.average();
+ }
+
+ @Override
+ public LongSummaryStatistics summaryStatistics() {
+ return s.summaryStatistics();
+ }
+
+ @Override
+ public boolean anyMatch(LongPredicate predicate) {
+ return s.anyMatch(predicate);
+ }
+
+ @Override
+ public boolean allMatch(LongPredicate predicate) {
+ return s.allMatch(predicate);
+ }
+
+ @Override
+ public boolean noneMatch(LongPredicate predicate) {
+ return s.noneMatch(predicate);
+ }
+
+ @Override
+ public OptionalLong findFirst() {
+ return s.findFirst();
+ }
+
+ @Override
+ public OptionalLong findAny() {
+ return s.findAny();
+ }
+
+ @Override
+ public DoubleStream asDoubleStream() {
+ return s.asDoubleStream();
+ }
+
+ @Override
+ public Stream<Long> boxed() {
+ return s.boxed();
+ }
+
+ @Override
+ public LongStream sequential() {
+ return s.sequential();
+ }
+
+ @Override
+ public LongStream parallel() {
+ return s.parallel();
+ }
+
+ @Override
+ public PrimitiveIterator.OfLong iterator() {
+ return s.iterator();
+ }
+
+ @Override
+ public Spliterator.OfLong spliterator() {
+ return s.spliterator();
+ }
+
+ @Override
+ public boolean isParallel() {
+ return s.isParallel();
+ }
+
+ @Override
+ public LongStream unordered() {
+ return s.unordered();
+ }
+
+ @Override
+ public LongStream onClose(Runnable closeHandler) {
+ return s.onClose(closeHandler);
+ }
+
+ @Override
+ public void close() {
+ s.close();
+ }
+ }
+
+ static final class DefaultMethodDoubleStream implements DoubleStream {
+ final DoubleStream s;
+
+ public DefaultMethodDoubleStream(DoubleStream s) {
+ this.s = s;
+ }
+
+ @Override
+ public DoubleStream filter(DoublePredicate predicate) {
+ return s.filter(predicate);
+ }
+
+ @Override
+ public DoubleStream map(DoubleUnaryOperator mapper) {
+ return s.map(mapper);
+ }
+
+ @Override
+ public <U> Stream<U> mapToObj(DoubleFunction<? extends U> mapper) {
+ return s.mapToObj(mapper);
+ }
+
+ @Override
+ public IntStream mapToInt(DoubleToIntFunction mapper) {
+ return s.mapToInt(mapper);
+ }
+
+ @Override
+ public LongStream mapToLong(DoubleToLongFunction mapper) {
+ return s.mapToLong(mapper);
+ }
+
+ @Override
+ public DoubleStream flatMap(DoubleFunction<? extends DoubleStream> mapper) {
+ return s.flatMap(mapper);
+ }
+
+ @Override
+ public DoubleStream distinct() {
+ return s.distinct();
+ }
+
+ @Override
+ public DoubleStream sorted() {
+ return s.sorted();
+ }
+
+ @Override
+ public DoubleStream peek(DoubleConsumer action) {
+ return s.peek(action);
+ }
+
+ @Override
+ public DoubleStream limit(long maxSize) {
+ return s.limit(maxSize);
+ }
+
+ @Override
+ public DoubleStream skip(long n) {
+ return s.skip(n);
+ }
+
+ @Override
+ public void forEach(DoubleConsumer action) {
+ s.forEach(action);
+ }
+
+ @Override
+ public void forEachOrdered(DoubleConsumer action) {
+ s.forEachOrdered(action);
+ }
+
+ @Override
+ public double[] toArray() {
+ return s.toArray();
+ }
+
+ @Override
+ public double reduce(double identity, DoubleBinaryOperator op) {
+ return s.reduce(identity, op);
+ }
+
+ @Override
+ public OptionalDouble reduce(DoubleBinaryOperator op) {
+ return s.reduce(op);
+ }
+
+ @Override
+ public <R> R collect(Supplier<R> supplier, ObjDoubleConsumer<R> accumulator, BiConsumer<R, R> combiner) {
+ return s.collect(supplier, accumulator, combiner);
+ }
+
+ @Override
+ public double sum() {
+ return s.sum();
+ }
+
+ @Override
+ public OptionalDouble min() {
+ return s.min();
+ }
+
+ @Override
+ public OptionalDouble max() {
+ return s.max();
+ }
+
+ @Override
+ public long count() {
+ return s.count();
+ }
+
+ @Override
+ public OptionalDouble average() {
+ return s.average();
+ }
+
+ @Override
+ public DoubleSummaryStatistics summaryStatistics() {
+ return s.summaryStatistics();
+ }
+
+ @Override
+ public boolean anyMatch(DoublePredicate predicate) {
+ return s.anyMatch(predicate);
+ }
+
+ @Override
+ public boolean allMatch(DoublePredicate predicate) {
+ return s.allMatch(predicate);
+ }
+
+ @Override
+ public boolean noneMatch(DoublePredicate predicate) {
+ return s.noneMatch(predicate);
+ }
+
+ @Override
+ public OptionalDouble findFirst() {
+ return s.findFirst();
+ }
+
+ @Override
+ public OptionalDouble findAny() {
+ return s.findAny();
+ }
+
+ @Override
+ public Stream<Double> boxed() {
+ return s.boxed();
+ }
+
+ @Override
+ public DoubleStream sequential() {
+ return s.sequential();
+ }
+
+ @Override
+ public DoubleStream parallel() {
+ return s.parallel();
+ }
+
+ @Override
+ public PrimitiveIterator.OfDouble iterator() {
+ return s.iterator();
+ }
+
+ @Override
+ public Spliterator.OfDouble spliterator() {
+ return s.spliterator();
+ }
+
+ @Override
+ public boolean isParallel() {
+ return s.isParallel();
+ }
+
+ @Override
+ public DoubleStream unordered() {
+ return s.unordered();
+ }
+
+ @Override
+ public DoubleStream onClose(Runnable closeHandler) {
+ return s.onClose(closeHandler);
+ }
+
+ @Override
+ public void close() {
+ s.close();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/DoubleStreamTestDataProvider.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+
+import java.util.*;
+import java.util.Spliterators;
+import java.util.function.Supplier;
+
+/** TestNG DataProvider for double-valued streams */
+public class DoubleStreamTestDataProvider {
+ private static final double[] to0 = new double[0];
+ private static final double[] to1 = new double[1];
+ private static final double[] to10 = new double[10];
+ private static final double[] to100 = new double[100];
+ private static final double[] to1000 = new double[1000];
+ private static final double[] reversed = new double[100];
+ private static final double[] ones = new double[100];
+ private static final double[] twice = new double[200];
+ private static final double[] pseudoRandom;
+
+ private static final Object[][] testData;
+ private static final Object[][] spliteratorTestData;
+
+ static {
+ double[][] arrays = {to0, to1, to10, to100, to1000};
+ for (double[] arr : arrays) {
+ for (int i = 0; i < arr.length; i++) {
+ arr[i] = i;
+ }
+ }
+ for (int i = 0; i < reversed.length; i++) {
+ reversed[i] = reversed.length - i;
+ }
+ for (int i = 0; i < ones.length; i++) {
+ ones[i] = 1;
+ }
+ System.arraycopy(to100, 0, twice, 0, to100.length);
+ System.arraycopy(to100, 0, twice, to100.length, to100.length);
+ pseudoRandom = new double[LambdaTestHelpers.LONG_STRING.length()];
+ for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
+ pseudoRandom[i] = (double) LambdaTestHelpers.LONG_STRING.charAt(i);
+ }
+ }
+
+ static final Object[][] arrays = {
+ {"empty", to0},
+ {"0..1", to1},
+ {"0..10", to10},
+ {"0..100", to100},
+ {"0..1000", to1000},
+ {"100x[1]", ones},
+ {"2x[0..100]", twice},
+ {"reverse 0..100", reversed},
+ {"pseudorandom", pseudoRandom}
+ };
+
+ static {
+ {
+ List<Object[]> list = new ArrayList<>();
+ for (Object[] data : arrays) {
+ final Object name = data[0];
+ final double[] doubles = (double[]) data[1];
+
+ list.add(new Object[]{"array:" + name,
+ TestData.Factory.ofArray("array:" + name, doubles)});
+
+ SpinedBuffer.OfDouble isl = new SpinedBuffer.OfDouble();
+ for (double i : doubles) {
+ isl.accept(i);
+ }
+ list.add(new Object[]{"SpinedList:" + name,
+ TestData.Factory.ofSpinedBuffer("SpinedList:" + name, isl)});
+ }
+ testData = list.toArray(new Object[0][]);
+ }
+
+ {
+ List<Object[]> spliterators = new ArrayList<>();
+ for (Object[] data : arrays) {
+ final Object name = data[0];
+ final double[] doubles = (double[]) data[1];
+
+ SpinedBuffer.OfDouble isl = new SpinedBuffer.OfDouble();
+ for (double i : doubles) {
+ isl.accept(i);
+ }
+
+ spliterators.add(splitDescr("Arrays.s(array):" + name,
+ () -> Arrays.spliterator(doubles)));
+ spliterators.add(splitDescr("Arrays.s(array,o,l):" + name,
+ () -> Arrays.spliterator(doubles, 0, doubles.length / 2)));
+
+ spliterators.add(splitDescr("SpinedBuffer.s():" + name,
+ () -> isl.spliterator()));
+
+ spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator(), size):" + name,
+ () -> Spliterators.spliterator(isl.iterator(), doubles.length, 0)));
+ spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator()):" + name,
+ () -> Spliterators.spliteratorUnknownSize(isl.iterator(), 0)));
+ // Need more!
+ }
+ spliteratorTestData = spliterators.toArray(new Object[0][]);
+ }
+
+ }
+
+ static <T> Object[] splitDescr(String description, Supplier<Spliterator.OfDouble> s) {
+ return new Object[] { description, s };
+ }
+
+ // Return an array of ( String name, DoubleStreamTestData )
+ @DataProvider(name = "DoubleStreamTestData")
+ public static Object[][] makeDoubleStreamTestData() {
+ return testData;
+ }
+
+ // returns an array of (String name, Supplier<PrimitiveSpliterator<Double>>)
+ @DataProvider(name = "DoubleSpliterator")
+ public static Object[][] spliteratorProvider() {
+ return spliteratorTestData;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/DoubleStreamTestScenario.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.PrimitiveIterator;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.Function;
+
+/**
+ * Test scenarios for double streams.
+ *
+ * Each scenario is provided with a data source, a function that maps a fresh
+ * stream (as provided by the data source) to a new stream, and a sink to
+ * receive results. Each scenario describes a different way of computing the
+ * stream contents. The test driver will ensure that all scenarios produce
+ * the same output (modulo allowable differences in ordering).
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public enum DoubleStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
+
+ STREAM_FOR_EACH(false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+ DoubleStream s = m.apply(source);
+ if (s.isParallel()) {
+ s = s.sequential();
+ }
+ s.forEach(b);
+ }
+ },
+
+ STREAM_TO_ARRAY(false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+ for (double t : m.apply(source).toArray()) {
+ b.accept(t);
+ }
+ }
+ },
+
+ STREAM_ITERATOR(false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+ for (PrimitiveIterator.OfDouble seqIter = m.apply(source).iterator(); seqIter.hasNext(); )
+ b.accept(seqIter.nextDouble());
+ }
+ },
+
+ // Wrap as stream, and spliterate then iterate in pull mode
+ STREAM_SPLITERATOR(false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+ for (Spliterator.OfDouble spl = m.apply(source).spliterator(); spl.tryAdvance(b); ) {
+ }
+ }
+ },
+
+ // Wrap as stream, spliterate, then split a few times mixing advances with forEach
+ STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+ SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(source).spliterator());
+ }
+ },
+
+ // Wrap as stream, and spliterate then iterate in pull mode
+ STREAM_SPLITERATOR_FOREACH(false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+ m.apply(source).spliterator().forEachRemaining(b);
+ }
+ },
+
+ PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+ m.apply(source).sequential().forEach(b);
+ }
+ },
+
+ // Wrap as parallel stream + forEachOrdered
+ PAR_STREAM_FOR_EACH_ORDERED(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+ // @@@ Want to explicitly select ordered equalator
+ m.apply(source).forEachOrdered(b);
+ }
+ },
+
+ // Wrap as stream, and spliterate then iterate sequentially
+ PAR_STREAM_SPLITERATOR(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+ for (Spliterator.OfDouble spl = m.apply(source).spliterator(); spl.tryAdvance(b); ) {
+ }
+ }
+ },
+
+ // Wrap as stream, and spliterate then iterate sequentially
+ PAR_STREAM_SPLITERATOR_FOREACH(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+ m.apply(source).spliterator().forEachRemaining(b);
+ }
+ },
+
+ PAR_STREAM_TO_ARRAY(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+ for (double t : m.apply(source).toArray())
+ b.accept(t);
+ }
+ },
+
+ // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
+ PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+ DoubleStream s = m.apply(source);
+ Spliterator.OfDouble sp = s.spliterator();
+ DoubleStream ss = StreamSupport.doubleStream(() -> sp,
+ StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
+ | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED), true);
+ for (double t : ss.toArray())
+ b.accept(t);
+ }
+ },
+
+ PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+ S_IN pipe1 = (S_IN) OpTestCase.chain(source,
+ new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+ DoubleStream pipe2 = m.apply(pipe1);
+
+ for (double t : pipe2.toArray())
+ b.accept(t);
+ }
+ },
+
+ // Wrap as parallel stream + forEach synchronizing
+ PAR_STREAM_FOR_EACH(true, false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+ m.apply(source).forEach(e -> {
+ synchronized (data) {
+ b.accept(e);
+ }
+ });
+ }
+ },
+
+ // Wrap as parallel stream + forEach synchronizing and clear SIZED flag
+ PAR_STREAM_FOR_EACH_CLEAR_SIZED(true, false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+ S_IN pipe1 = (S_IN) OpTestCase.chain(source,
+ new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+ m.apply(pipe1).forEach(e -> {
+ synchronized (data) {
+ b.accept(e);
+ }
+ });
+ }
+ },
+ ;
+
+ // The set of scenarios that clean the SIZED flag
+ public static final Set<DoubleStreamTestScenario> CLEAR_SIZED_SCENARIOS = Collections.unmodifiableSet(
+ EnumSet.of(PAR_STREAM_TO_ARRAY_CLEAR_SIZED, PAR_STREAM_FOR_EACH_CLEAR_SIZED));
+
+ private boolean isParallel;
+
+ private final boolean isOrdered;
+
+ DoubleStreamTestScenario(boolean isParallel) {
+ this(isParallel, true);
+ }
+
+ DoubleStreamTestScenario(boolean isParallel, boolean isOrdered) {
+ this.isParallel = isParallel;
+ this.isOrdered = isOrdered;
+ }
+
+ public StreamShape getShape() {
+ return StreamShape.DOUBLE_VALUE;
+ }
+
+ public boolean isParallel() {
+ return isParallel;
+ }
+
+ public boolean isOrdered() {
+ return isOrdered;
+ }
+
+ public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+ void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
+ try (S_IN source = getStream(data)) {
+ run(data, source, (DoubleConsumer) b, (Function<S_IN, DoubleStream>) m);
+ }
+ }
+
+ abstract <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/FlagDeclaringOp.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * An operation that injects or clears flags but otherwise performs no operation on elements.
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class FlagDeclaringOp<T> implements StatelessTestOp<T, T> {
+ private final int flags;
+ private final StreamShape shape;
+
+ public FlagDeclaringOp(int flags) {
+ this(flags, StreamShape.REFERENCE);
+ }
+
+ public FlagDeclaringOp(int flags, StreamShape shape) {
+ this.flags = flags;
+ this.shape = shape;
+ }
+
+ @Override
+ public StreamShape outputShape() {
+ return shape;
+ }
+
+ @Override
+ public StreamShape inputShape() {
+ return shape;
+ }
+
+ @Override
+ public int opGetFlags() {
+ return flags;
+ }
+
+ @Override
+ public Sink<T> opWrapSink(int flags, boolean parallel, Sink sink) {
+ return sink;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/IntStreamTestDataProvider.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+
+import java.util.*;
+import java.util.Spliterators;
+import java.util.function.Supplier;
+
+/** TestNG DataProvider for int-valued streams */
+public class IntStreamTestDataProvider {
+ private static final int[] to0 = new int[0];
+ private static final int[] to1 = new int[1];
+ private static final int[] to10 = new int[10];
+ private static final int[] to100 = new int[100];
+ private static final int[] to1000 = new int[1000];
+ private static final int[] reversed = new int[100];
+ private static final int[] ones = new int[100];
+ private static final int[] twice = new int[200];
+ private static final int[] pseudoRandom;
+
+ private static final Object[][] testData;
+ private static final Object[][] spliteratorTestData;
+
+ static {
+ int[][] arrays = {to0, to1, to10, to100, to1000};
+ for (int[] arr : arrays) {
+ for (int i = 0; i < arr.length; i++) {
+ arr[i] = i;
+ }
+ }
+ for (int i = 0; i < reversed.length; i++) {
+ reversed[i] = reversed.length - i;
+ }
+ for (int i = 0; i < ones.length; i++) {
+ ones[i] = 1;
+ }
+ System.arraycopy(to100, 0, twice, 0, to100.length);
+ System.arraycopy(to100, 0, twice, to100.length, to100.length);
+ pseudoRandom = new int[LambdaTestHelpers.LONG_STRING.length()];
+ for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
+ pseudoRandom[i] = (int) LambdaTestHelpers.LONG_STRING.charAt(i);
+ }
+ }
+
+ static final Object[][] arrays = {
+ {"empty", to0},
+ {"0..1", to1},
+ {"0..10", to10},
+ {"0..100", to100},
+ {"0..1000", to1000},
+ {"100x[1]", ones},
+ {"2x[0..100]", twice},
+ {"reverse 0..100", reversed},
+ {"pseudorandom", pseudoRandom}
+ };
+
+ static {
+ {
+ List<Object[]> list = new ArrayList<>();
+ for (Object[] data : arrays) {
+ final Object name = data[0];
+ final int[] ints = (int[]) data[1];
+
+ list.add(new Object[]{"array:" +
+ name, TestData.Factory.ofArray("array:" + name, ints)});
+
+ SpinedBuffer.OfInt isl = new SpinedBuffer.OfInt();
+ for (int i : ints) {
+ isl.accept(i);
+ }
+ list.add(new Object[]{"SpinedList:" + name,
+ TestData.Factory.ofSpinedBuffer("SpinedList:" + name, isl)});
+
+ list.add(streamDataDescr("IntStream.intRange(0,l): " + ints.length,
+ () -> IntStream.range(0, ints.length)));
+ list.add(streamDataDescr("IntStream.rangeClosed(0,l): " + ints.length,
+ () -> IntStream.rangeClosed(0, ints.length)));
+ }
+ testData = list.toArray(new Object[0][]);
+ }
+
+ {
+ List<Object[]> spliterators = new ArrayList<>();
+ for (Object[] data : arrays) {
+ final Object name = data[0];
+ final int[] ints = (int[]) data[1];
+
+ SpinedBuffer.OfInt isl = new SpinedBuffer.OfInt();
+ for (int i : ints) {
+ isl.accept(i);
+ }
+
+ spliterators.add(splitDescr("Arrays.s(array):" + name,
+ () -> Arrays.spliterator(ints)));
+ spliterators.add(splitDescr("Arrays.s(array,o,l):" + name,
+ () -> Arrays.spliterator(ints, 0, ints.length / 2)));
+
+ spliterators.add(splitDescr("SpinedBuffer.s():" + name,
+ () -> isl.spliterator()));
+
+ spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator(), size):" + name,
+ () -> Spliterators.spliterator(isl.iterator(), ints.length, 0)));
+ spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator()):" + name,
+ () -> Spliterators.spliteratorUnknownSize(isl.iterator(), 0)));
+
+ spliterators.add(splitDescr("IntStream.intRange(0,l):" + name,
+ () -> IntStream.range(0, ints.length).spliterator()));
+ spliterators.add(splitDescr("IntStream.intRangeClosed(0,l):" + name,
+ () -> IntStream.rangeClosed(0, ints.length).spliterator()));
+ // Need more!
+ }
+ spliteratorTestData = spliterators.toArray(new Object[0][]);
+ }
+
+ }
+
+ static <T> Object[] streamDataDescr(String description, Supplier<IntStream> s) {
+ return new Object[] { description, TestData.Factory.ofIntSupplier(description, s) };
+ }
+
+ static <T> Object[] splitDescr(String description, Supplier<Spliterator.OfInt> s) {
+ return new Object[] { description, s };
+ }
+
+ // Return an array of ( String name, IntStreamTestData )
+ @DataProvider(name = "IntStreamTestData")
+ public static Object[][] makeIntStreamTestData() {
+ return testData;
+ }
+
+ // returns an array of (String name, Supplier<PrimitiveSpliterator<Integer>>)
+ @DataProvider(name = "IntSpliterator")
+ public static Object[][] spliteratorProvider() {
+ return spliteratorTestData;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/IntStreamTestScenario.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.PrimitiveIterator;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+
+/**
+ * Test scenarios for int streams.
+ *
+ * Each scenario is provided with a data source, a function that maps a fresh
+ * stream (as provided by the data source) to a new stream, and a sink to
+ * receive results. Each scenario describes a different way of computing the
+ * stream contents. The test driver will ensure that all scenarios produce
+ * the same output (modulo allowable differences in ordering).
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public enum IntStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
+
+ STREAM_FOR_EACH(false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
+ IntStream s = m.apply(source);
+ if (s.isParallel()) {
+ s = s.sequential();
+ }
+ s.forEach(b);
+ }
+ },
+
+ STREAM_TO_ARRAY(false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
+ for (int t : m.apply(source).toArray()) {
+ b.accept(t);
+ }
+ }
+ },
+
+ STREAM_ITERATOR(false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
+ for (PrimitiveIterator.OfInt seqIter = m.apply(source).iterator(); seqIter.hasNext(); )
+ b.accept(seqIter.nextInt());
+ }
+ },
+
+ // Wrap as stream, and spliterate then iterate in pull mode
+ STREAM_SPLITERATOR(false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
+ for (Spliterator.OfInt spl = m.apply(source).spliterator(); spl.tryAdvance(b); ) {
+ }
+ }
+ },
+
+ // Wrap as stream, spliterate, then split a few times mixing advances with forEach
+ STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
+ SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(source).spliterator());
+ }
+ },
+
+ // Wrap as stream, and spliterate then iterate in pull mode
+ STREAM_SPLITERATOR_FOREACH(false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
+ m.apply(source).spliterator().forEachRemaining(b);
+ }
+ },
+
+ PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
+ m.apply(source).sequential().forEach(b);
+ }
+ },
+
+ // Wrap as parallel stream + forEachOrdered
+ PAR_STREAM_FOR_EACH_ORDERED(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
+ // @@@ Want to explicitly select ordered equalator
+ m.apply(source).forEachOrdered(b);
+ }
+ },
+
+ // Wrap as stream, and spliterate then iterate sequentially
+ PAR_STREAM_SPLITERATOR(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
+ for (Spliterator.OfInt spl = m.apply(source).spliterator(); spl.tryAdvance(b); ) {
+ }
+ }
+ },
+
+ // Wrap as stream, and spliterate then iterate sequentially
+ PAR_STREAM_SPLITERATOR_FOREACH(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
+ m.apply(source).spliterator().forEachRemaining(b);
+ }
+ },
+
+ PAR_STREAM_TO_ARRAY(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
+ for (int t : m.apply(source).toArray())
+ b.accept(t);
+ }
+ },
+
+ // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
+ PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
+ IntStream s = m.apply(source);
+ Spliterator.OfInt sp = s.spliterator();
+ IntStream ss = StreamSupport.intStream(() -> sp,
+ StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
+ | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED),
+ true);
+ for (int t : ss.toArray())
+ b.accept(t);
+ }
+ },
+
+ PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
+ S_IN pipe1 = (S_IN) OpTestCase.chain(source,
+ new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+ IntStream pipe2 = m.apply(pipe1);
+
+ for (int t : pipe2.toArray())
+ b.accept(t);
+ }
+ },
+
+ // Wrap as parallel stream + forEach synchronizing
+ PAR_STREAM_FOR_EACH(true, false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
+ m.apply(source).forEach(e -> {
+ synchronized (data) {
+ b.accept(e);
+ }
+ });
+ }
+ },
+
+ // Wrap as parallel stream + forEach synchronizing and clear SIZED flag
+ PAR_STREAM_FOR_EACH_CLEAR_SIZED(true, false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
+ S_IN pipe1 = (S_IN) OpTestCase.chain(source,
+ new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+ m.apply(pipe1).forEach(e -> {
+ synchronized (data) {
+ b.accept(e);
+ }
+ });
+ }
+ },
+ ;
+
+ // The set of scenarios that clean the SIZED flag
+ public static final Set<IntStreamTestScenario> CLEAR_SIZED_SCENARIOS = Collections.unmodifiableSet(
+ EnumSet.of(PAR_STREAM_TO_ARRAY_CLEAR_SIZED, PAR_STREAM_FOR_EACH_CLEAR_SIZED));
+
+ private final boolean isParallel;
+
+ private final boolean isOrdered;
+
+ IntStreamTestScenario(boolean isParallel) {
+ this(isParallel, true);
+ }
+
+ IntStreamTestScenario(boolean isParallel, boolean isOrdered) {
+ this.isParallel = isParallel;
+ this.isOrdered = isOrdered;
+ }
+
+ public StreamShape getShape() {
+ return StreamShape.INT_VALUE;
+ }
+
+ public boolean isParallel() {
+ return isParallel;
+ }
+
+ public boolean isOrdered() {
+ return isOrdered;
+ }
+
+ public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+ void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
+ try (S_IN source = getStream(data)) {
+ run(data, source, (IntConsumer) b, (Function<S_IN, IntStream>) m);
+ }
+ }
+
+ abstract <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/IntermediateTestOp.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * A base type for test operations
+ */
+interface IntermediateTestOp<E_IN, E_OUT> {
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public static<T> AbstractPipeline chain(AbstractPipeline upstream,
+ IntermediateTestOp<?, T> op) {
+ if (op instanceof StatelessTestOp)
+ return StatelessTestOp.chain(upstream, (StatelessTestOp) op);
+
+ if (op instanceof StatefulTestOp)
+ return StatefulTestOp.chain(upstream, (StatefulTestOp) op);
+
+ throw new IllegalStateException("Unknown test op type: " + op.getClass().getName());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/LambdaTestHelpers.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,462 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.*;
+import java.util.function.BiConsumer;
+import java.util.function.BiPredicate;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoublePredicate;
+import java.util.function.Function;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.IntPredicate;
+import java.util.function.IntUnaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongConsumer;
+import java.util.function.LongPredicate;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * LambdaTestHelpers -- assertion methods and useful objects for lambda test cases
+ */
+public class LambdaTestHelpers {
+ public static final String LONG_STRING = "When in the Course of human events it becomes necessary for one people to dissolve the political bands which have connected them with another and to assume among the powers of the earth, the separate and equal station to which the Laws of Nature and of Nature's God entitle them, a decent respect to the opinions of mankind requires that they should declare the causes which impel them to the separation.";
+
+ @SuppressWarnings("rawtypes")
+ public static final Consumer bEmpty = x -> { };
+ @SuppressWarnings("rawtypes")
+ public static final IntConsumer bIntEmpty = x -> { };
+ @SuppressWarnings("rawtypes")
+ public static final BiConsumer bBiEmpty = (x,y) -> { };
+ @SuppressWarnings("rawtypes")
+ public static final Consumer bHashCode = x -> { Objects.hashCode(x); };
+ @SuppressWarnings("rawtypes")
+ public static final BiConsumer bBiHashCode = (x,y) -> { Objects.hash(x, y); };
+ public static final Function<Integer, Integer> mZero = x -> 0;
+ public static final Function<Integer, Integer> mId = x -> x;
+ public static final Function<Integer, Integer> mDoubler = x -> x * 2;
+ public static final Function<Integer, Stream<Integer>> mfId = e -> Collections.singletonList(e).stream();
+ public static final Function<Integer, Stream<Integer>> mfNull = e -> Collections.<Integer>emptyList().stream();
+ public static final Function<Integer, Stream<Integer>> mfLt = e -> {
+ List<Integer> l = new ArrayList<>();
+ for (int i=0; i<e; i++)
+ l.add(i);
+ return l.stream();
+ };
+ public static final ToIntFunction<Integer> imDoubler = x -> x * 2;
+ public static final ToLongFunction<Long> lmDoubler = x -> x * 2;
+ public static final ToDoubleFunction<Double> dmDoubler = x -> x * 2;
+ public static final Predicate<Integer> pFalse = x -> false;
+ public static final Predicate<Integer> pTrue = x -> true;
+ public static final Predicate<Integer> pEven = x -> 0 == x % 2;
+ public static final Predicate<Integer> pOdd = x -> 1 == x % 2;
+ public static final IntPredicate ipFalse = x -> false;
+ public static final IntPredicate ipTrue = x -> true;
+ public static final IntPredicate ipEven = x -> 0 == x % 2;
+ public static final IntPredicate ipOdd = x -> 1 == x % 2;
+ public static final LongPredicate lpFalse = x -> false;
+ public static final LongPredicate lpTrue = x -> true;
+ public static final LongPredicate lpEven = x -> 0 == x % 2;
+ public static final LongPredicate lpOdd = x -> 1 == x % 2;
+ public static final DoublePredicate dpFalse = x -> false;
+ public static final DoublePredicate dpTrue = x -> true;
+ public static final DoublePredicate dpEven = x -> 0 == ((long) x) % 2;
+ public static final DoublePredicate dpOdd = x -> 1 == ((long) x) % 2;
+ public static final BinaryOperator<Integer> rPlus = (x, y) -> x+y;
+ public static final BinaryOperator<Integer> rMax = (x, y) -> Math.max(x, y);
+ public static final BinaryOperator<Integer> rMin = (x, y) -> Math.min(x,y);
+ public static final IntBinaryOperator irPlus = (x, y) -> x+y;
+ public static final IntBinaryOperator irMax = (x, y) -> Math.max(x, y);
+ public static final IntBinaryOperator irMin = (x, y) -> Math.min(x,y);
+ public static final IntUnaryOperator irDoubler = x -> x * 2;
+ public static final LongBinaryOperator lrPlus = (x, y) -> x+y;
+ public static final DoubleBinaryOperator drPlus = (x, y) -> x+y;
+ public static final Comparator<Integer> cInteger = (a, b) -> Integer.compare(a, b);
+ public static final BiPredicate<?, ?> bipFalse = (x, y) -> false;
+ public static final BiPredicate<?, ?> bipTrue = (x, y) -> true;
+ public static final BiPredicate<Integer, Integer> bipBothEven = (x, y) -> 0 == (x % 2 + y % 2);
+ public static final BiPredicate<Integer, Integer> bipBothOdd = (x, y) -> 2 == (x % 2 + y % 2);
+ public static final BiPredicate<?, ?> bipSameString = (x, y) -> String.valueOf(x).equals(String.valueOf(y));
+
+ public static final IntFunction<Integer[]> integerArrayGenerator = s -> new Integer[s];
+
+ public static final IntFunction<Object[]> objectArrayGenerator = s -> new Object[s];
+
+ public static final Function<String, Stream<Character>> flattenChars = string -> {
+ List<Character> l = new ArrayList<>();
+ for (int i=0; i<string.length(); i++)
+ l.add(string.charAt(i));
+ return l.stream();
+ };
+
+ public static final Function<String, IntStream> flattenInt
+ = string -> IntStream.range(0, string.length()).map(string::charAt);
+
+ public static <T, R> Function<T, R> forPredicate(Predicate<? super T> predicate, R forTrue, R forFalse) {
+ Objects.requireNonNull(predicate);
+
+ return t -> predicate.test(t) ? forTrue : forFalse;
+ }
+
+ public static <T> Function<T, T> identity() {
+ return t -> t;
+ }
+
+ public static<V, T, R> Function<V, R> compose(Function<? super T, ? extends R> after, Function<? super V, ? extends T> before) {
+ Objects.requireNonNull(before);
+ return (V v) -> after.apply(before.apply(v));
+ }
+
+ public static List<Integer> empty() {
+ ArrayList<Integer> list = new ArrayList<>();
+ list.add(null);
+ return list;
+ }
+
+ public static List<Integer> countTo(int n) {
+ return range(1, n);
+ }
+
+ public static List<Integer> range(int l, int u) {
+ ArrayList<Integer> list = new ArrayList<>(u - l + 1);
+ for (int i=l; i<=u; i++) {
+ list.add(i);
+ }
+ return list;
+ }
+
+ public static List<Integer> repeat(int value, int n) {
+ ArrayList<Integer> list = new ArrayList<>(n);
+ for (int i=1; i<=n; i++) {
+ list.add(value);
+ }
+ return list;
+ }
+
+ public static List<Double> asDoubles(List<Integer> integers) {
+ ArrayList<Double> list = new ArrayList<>();
+ for (Integer i : integers) {
+ list.add((double) i);
+ }
+ return list;
+ }
+
+ public static List<Long> asLongs(List<Integer> integers) {
+ ArrayList<Long> list = new ArrayList<>();
+ for (Integer i : integers) {
+ list.add((long) i);
+ }
+ return list;
+ }
+
+ public static void assertCountSum(Stream<? super Integer> it, int count, int sum) {
+ assertCountSum(it.iterator(), count, sum);
+ }
+
+ public static void assertCountSum(Iterable<? super Integer> it, int count, int sum) {
+ assertCountSum(it.iterator(), count, sum);
+ }
+
+ public static void assertCountSum(Iterator<? super Integer> it, int count, int sum) {
+ int c = 0;
+ int s = 0;
+ while (it.hasNext()) {
+ int i = (Integer) it.next();
+ c++;
+ s += i;
+ }
+
+ assertEquals(c, count);
+ assertEquals(s, sum);
+ }
+
+ public static void assertConcat(Iterator<Character> it, String result) {
+ StringBuilder sb = new StringBuilder();
+ while (it.hasNext()) {
+ sb.append(it.next());
+ }
+
+ assertEquals(result, sb.toString());
+ }
+
+ public static<T extends Comparable<? super T>> void assertSorted(Iterator<T> i) {
+ i = toBoxedList(i).iterator();
+
+ if (!i.hasNext())
+ return;
+ T last = i.next();
+ while (i.hasNext()) {
+ T t = i.next();
+ assertTrue(last.compareTo(t) <= 0);
+ assertTrue(t.compareTo(last) >= 0);
+ last = t;
+ }
+ }
+
+ public static<T> void assertSorted(Iterator<T> i, Comparator<? super T> comp) {
+ if (i instanceof PrimitiveIterator.OfInt
+ || i instanceof PrimitiveIterator.OfDouble
+ || i instanceof PrimitiveIterator.OfLong) {
+ i = toBoxedList(i).iterator();
+ }
+
+ if (!i.hasNext())
+ return;
+ T last = i.next();
+ while (i.hasNext()) {
+ T t = i.next();
+ assertTrue(comp.compare(last, t) <= 0);
+ assertTrue(comp.compare(t, last) >= 0);
+ last = t;
+ }
+ }
+
+ public static<T extends Comparable<? super T>> void assertSorted(Iterable<T> iter) {
+ assertSorted(iter.iterator());
+ }
+
+ public static<T> void assertSorted(Iterable<T> iter, Comparator<? super T> comp) {
+ assertSorted(iter.iterator(), comp);
+ }
+
+ public static <T> void assertUnique(Iterable<T> iter) {
+ assertUnique(iter.iterator());
+ }
+
+ public static<T> void assertUnique(Iterator<T> iter) {
+ if (!iter.hasNext()) {
+ return;
+ }
+
+ if (iter instanceof PrimitiveIterator.OfInt
+ || iter instanceof PrimitiveIterator.OfDouble
+ || iter instanceof PrimitiveIterator.OfLong) {
+ iter = toBoxedList(iter).iterator();
+ }
+
+ Set<T> uniq = new HashSet<>();
+ while(iter.hasNext()) {
+ T each = iter.next();
+ assertTrue(!uniq.contains(each), "Not unique");
+ uniq.add(each);
+ }
+ }
+
+ public static<T> void assertContents(Iterable<T> actual, Iterable<T> expected) {
+ if (actual instanceof Collection && expected instanceof Collection) {
+ assertEquals(actual, expected);
+ } else {
+ assertContents(actual.iterator(), expected.iterator());
+ }
+ }
+
+ public static<T> void assertContents(Iterator<T> actual, Iterator<T> expected) {
+ assertEquals(toBoxedList(actual), toBoxedList(expected));
+ }
+
+ @SafeVarargs
+ @SuppressWarnings("varargs")
+ public static<T> void assertContents(Iterator<T> actual, T... expected) {
+ assertContents(actual, Arrays.asList(expected).iterator());
+ }
+
+ /**
+ * The all consuming consumer (rampant capitalist) that can accepting a reference or any primitive value.
+ */
+ private static interface OmnivorousConsumer<T>
+ extends Consumer<T>, IntConsumer, LongConsumer, DoubleConsumer { }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public static<T> Consumer<T> toBoxingConsumer(Consumer<? super T> c) {
+ return (Consumer<T>) new OmnivorousConsumer() {
+ @Override
+ public void accept(Object t) {
+ c.accept((T) t);
+ }
+
+ @Override
+ public void accept(int t) {
+ accept((Object) t);
+ }
+
+ @Override
+ public void accept(long t) {
+ accept((Object) t);
+ }
+
+ @Override
+ public void accept(double t) {
+ accept((Object) t);
+ }
+ };
+ }
+
+ /**
+ * Convert an iterator to a list using forEach with an implementation of
+ * {@link java.util.stream.LambdaTestHelpers.OmnivorousConsumer}.
+ *
+ * This ensures equality comparisons for test results do not trip
+ * the boxing trip-wires.
+ */
+ private static<T> List<T> toBoxedList(Iterator<T> it) {
+ List<T> l = new ArrayList<>();
+ it.forEachRemaining(toBoxingConsumer(l::add));
+ return l;
+ }
+
+ /**
+ * Convert a spliterator to a list using forEach with an implementation of
+ * {@link java.util.stream.LambdaTestHelpers.OmnivorousConsumer}.
+ *
+ * This ensures equality comparisons for test results do not trip
+ * the boxing trip-wires.
+ */
+ public static<T> List<T> toBoxedList(Spliterator<T> sp) {
+ List<T> l = new ArrayList<>();
+ sp.forEachRemaining(toBoxingConsumer(l::add));
+ return l;
+ }
+
+ /**
+ * Convert an iterator to a multi-set, represented as a Map, using forEach with an implementation of
+ * {@link java.util.stream.LambdaTestHelpers.OmnivorousConsumer}.
+ *
+ * This ensures equality comparisons for test results do not trip
+ * the boxing trip-wires.
+ */
+ @SuppressWarnings("unchecked")
+ private static<T> Map<T, Integer> toBoxedMultiset(Iterator<T> it) {
+ Map<Object, Integer> result = new HashMap<>();
+
+ it.forEachRemaining(toBoxingConsumer(o -> {
+ if (result.containsKey(o))
+ result.put(o, result.get(o) + 1);
+ else
+ result.put(o, 1);
+ }));
+
+ return (Map<T, Integer>) result;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static<T> Map<T, Integer> toBoxedMultiset(Spliterator<T> it) {
+ Map<Object, Integer> result = new HashMap<>();
+
+ it.forEachRemaining(toBoxingConsumer(o -> {
+ if (result.containsKey(o))
+ result.put(o, result.get(o) + 1);
+ else
+ result.put(o, 1);
+ }));
+
+ return (Map<T, Integer>) result;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static void assertContentsEqual(Object a, Object b) {
+ if (a instanceof Iterable && b instanceof Iterable)
+ assertContents((Iterable) a, (Iterable) b);
+ else
+ assertEquals(a, b);
+ }
+
+ public static<T> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected) {
+ assertContentsUnordered(actual.iterator(), expected.iterator());
+ }
+
+ public static<T> void assertContentsUnordered(Iterator<T> actual, Iterator<T> expected) {
+ assertEquals(toBoxedMultiset(actual), toBoxedMultiset(expected));
+ }
+
+ public static void launderAssertion(Runnable r, Supplier<String> additionalInfo) {
+ try {
+ r.run();
+ }
+ catch (AssertionError ae) {
+ AssertionError cloned = new AssertionError(ae.getMessage() + String.format("%n%s", additionalInfo.get()));
+ cloned.setStackTrace(ae.getStackTrace());
+ if (ae.getCause() != null)
+ cloned.initCause(ae.getCause());
+ throw cloned;
+ }
+ }
+
+ public static <T, S extends BaseStream<T, S>>
+ List<Function<S, S>> permuteStreamFunctions(List<Function<S, S>> opFunctions) {
+ List<List<Function<S, S>>> opFunctionPermutations = perm(opFunctions);
+
+ List<Function<S, S>> appliedFunctions = new ArrayList<>();
+ for (List<Function<S, S>> fs : opFunctionPermutations) {
+ Function<S, S> applied = s -> {
+ for (Function<S, S> f : fs) {
+ s = f.apply(s);
+ }
+ return s;
+ };
+ appliedFunctions.add(applied);
+ }
+
+ return appliedFunctions;
+ }
+
+ private static <T> List<T> sub(List<T> l, int index) {
+ List<T> subL = new ArrayList<>(l);
+ subL.remove(index);
+ return subL;
+ }
+
+ public static <T> List<List<T>> perm(List<T> l) {
+ List<List<T>> result = new ArrayList<>();
+ for (int i = 0; i < l.size(); i++) {
+ for (List<T> perm : perm(sub(l, i))) {
+ perm.add(0, l.get(i));
+ result.add(perm);
+ }
+ }
+ result.add(new ArrayList<T>());
+
+ return result;
+ }
+
+ public static String flagsToString(int flags) {
+ StringJoiner sj = new StringJoiner(", ", "StreamOpFlag[", "]");
+ if (StreamOpFlag.DISTINCT.isKnown(flags)) sj.add("IS_DISTINCT");
+ if (StreamOpFlag.ORDERED.isKnown(flags)) sj.add("IS_ORDERED");
+ if (StreamOpFlag.SIZED.isKnown(flags)) sj.add("IS_SIZED");
+ if (StreamOpFlag.SORTED.isKnown(flags)) sj.add("IS_SORTED");
+ if (StreamOpFlag.SHORT_CIRCUIT.isKnown(flags)) sj.add("IS_SHORT_CIRCUIT");
+ return sj.toString();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/LambdaTestMode.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * Runtime modes of test execution.
+ */
+public enum LambdaTestMode {
+ /**
+ * Execution mode with no particular runtime constraints.
+ */
+ NORMAL,
+
+ /**
+ * Execution mode where tests are executed for testing lambda serialization
+ * and deserialization.
+ *
+ * <p>This mode may be queried by tests or data supplied by data
+ * providers, which cannot otherwise be assigned to the test group
+ * <em>serialization-hostile</em>, to not execute or declare
+ * serialization-hostile code or data.
+ *
+ * <p>This mode is enabled if the boolean system property
+ * {@code org.openjdk.java.util.stream.sand.mode} is declared with a
+ * {@code true} value.
+ */
+ SERIALIZATION;
+
+ /**
+ * {@code true} if tests are executed in the mode for testing lambda
+ * Serialization ANd Deserialization (SAND).
+ */
+ private static final boolean IS_LAMBDA_SERIALIZATION_MODE =
+ Boolean.getBoolean("org.openjdk.java.util.stream.sand.mode");
+
+ /**
+ *
+ * @return the mode of test execution.
+ */
+ public static LambdaTestMode getMode() {
+ return IS_LAMBDA_SERIALIZATION_MODE ? SERIALIZATION : NORMAL;
+ }
+
+ /**
+ *
+ * @return {@code true} if normal test mode.
+ */
+ public static boolean isNormalMode() {
+ return getMode() == NORMAL;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/LoggingTestCase.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.testng.Assert;
+import org.testng.ITestResult;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ * LoggingTestCase
+ *
+ */
+@Test
+public class LoggingTestCase extends Assert {
+ private Map<String, Object> context = new HashMap<>();
+
+ @BeforeMethod
+ public void before() {
+ context.clear();
+ }
+
+ @AfterMethod
+ public void after(ITestResult result) {
+ if (!result.isSuccess()) {
+ List<Object> list = new ArrayList<>();
+ Collections.addAll(list, result.getParameters());
+ list.add(context.toString());
+ result.setParameters(list.toArray(new Object[list.size()]));
+ }
+ }
+
+ protected void setContext(String key, Object value) {
+ context.put(key, value);
+ }
+
+ protected void clearContext(String key) {
+ context.remove(key);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/LongStreamTestDataProvider.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+
+import java.util.*;
+import java.util.Spliterators;
+import java.util.function.Supplier;
+
+/** TestNG DataProvider for long-valued streams */
+public class LongStreamTestDataProvider {
+ private static final long[] to0 = new long[0];
+ private static final long[] to1 = new long[1];
+ private static final long[] to10 = new long[10];
+ private static final long[] to100 = new long[100];
+ private static final long[] to1000 = new long[1000];
+ private static final long[] reversed = new long[100];
+ private static final long[] ones = new long[100];
+ private static final long[] twice = new long[200];
+ private static final long[] pseudoRandom;
+
+ private static final Object[][] testData;
+ private static final Object[][] spliteratorTestData;
+
+ static {
+ long[][] arrays = {to0, to1, to10, to100, to1000};
+ for (long[] arr : arrays) {
+ for (int i = 0; i < arr.length; i++) {
+ arr[i] = i;
+ }
+ }
+ for (int i = 0; i < reversed.length; i++) {
+ reversed[i] = reversed.length - i;
+ }
+ for (int i = 0; i < ones.length; i++) {
+ ones[i] = 1;
+ }
+ System.arraycopy(to100, 0, twice, 0, to100.length);
+ System.arraycopy(to100, 0, twice, to100.length, to100.length);
+ pseudoRandom = new long[LambdaTestHelpers.LONG_STRING.length()];
+ for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
+ pseudoRandom[i] = (long) LambdaTestHelpers.LONG_STRING.charAt(i);
+ }
+ }
+
+ static final Object[][] arrays = {
+ {"empty", to0},
+ {"0..1", to1},
+ {"0..10", to10},
+ {"0..100", to100},
+ {"0..1000", to1000},
+ {"100x[1]", ones},
+ {"2x[0..100]", twice},
+ {"reverse 0..100", reversed},
+ {"pseudorandom", pseudoRandom}
+ };
+
+ static {
+ {
+ List<Object[]> list = new ArrayList<>();
+ for (Object[] data : arrays) {
+ final Object name = data[0];
+ final long[] longs = (long[]) data[1];
+
+ list.add(new Object[]{"array:" + name,
+ TestData.Factory.ofArray("array:" + name, longs)});
+
+ SpinedBuffer.OfLong isl = new SpinedBuffer.OfLong();
+ for (long i : longs) {
+ isl.accept(i);
+ }
+ list.add(new Object[]{"SpinedList:" + name,
+ TestData.Factory.ofSpinedBuffer("SpinedList:" + name, isl)});
+
+ list.add(streamDataDescr("LongStream.longRange(0,l): " + longs.length,
+ () -> LongStream.range(0, longs.length)));
+ list.add(streamDataDescr("LongStream.longRangeClosed(0,l): " + longs.length,
+ () -> LongStream.rangeClosed(0, longs.length)));
+ }
+ testData = list.toArray(new Object[0][]);
+ }
+
+ {
+ List<Object[]> spliterators = new ArrayList<>();
+ for (Object[] data : arrays) {
+ final Object name = data[0];
+ final long[] longs = (long[]) data[1];
+
+ SpinedBuffer.OfLong isl = new SpinedBuffer.OfLong();
+ for (long i : longs) {
+ isl.accept(i);
+ }
+
+ spliterators.add(splitDescr("Arrays.s(array):" + name,
+ () -> Arrays.spliterator(longs)));
+ spliterators.add(splitDescr("Arrays.s(array,o,l):" + name,
+ () -> Arrays.spliterator(longs, 0, longs.length / 2)));
+
+ spliterators.add(splitDescr("SpinedBuffer.s():" + name,
+ () -> isl.spliterator()));
+
+ spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator(), size):" + name,
+ () -> Spliterators.spliterator(isl.iterator(), longs.length, 0)));
+ spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator()):" + name,
+ () -> Spliterators.spliteratorUnknownSize(isl.iterator(), 0)));
+
+ spliterators.add(splitDescr("LongStream.longRange(0,l):" + name,
+ () -> LongStream.range(0, longs.length).spliterator()));
+ spliterators.add(splitDescr("LongStream.longRangeClosed(0,l):" + name,
+ () -> LongStream.rangeClosed(0, longs.length).spliterator()));
+ // Need more!
+ }
+ spliteratorTestData = spliterators.toArray(new Object[0][]);
+ }
+
+ }
+
+ static <T> Object[] streamDataDescr(String description, Supplier<LongStream> s) {
+ return new Object[] { description, TestData.Factory.ofLongSupplier(description, s) };
+ }
+
+ static <T> Object[] splitDescr(String description, Supplier<Spliterator.OfLong> s) {
+ return new Object[] { description, s };
+ }
+
+ // Return an array of ( String name, LongStreamTestData )
+ @DataProvider(name = "LongStreamTestData")
+ public static Object[][] makeLongStreamTestData() {
+ return testData;
+ }
+
+ // returns an array of (String name, Supplier<PrimitiveSpliterator<Long>>)
+ @DataProvider(name = "LongSpliterator")
+ public static Object[][] spliteratorProvider() {
+ return spliteratorTestData;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/LongStreamTestScenario.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.PrimitiveIterator;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.LongConsumer;
+
+/**
+ * Test scenarios for long streams.
+ *
+ * Each scenario is provided with a data source, a function that maps a fresh
+ * stream (as provided by the data source) to a new stream, and a sink to
+ * receive results. Each scenario describes a different way of computing the
+ * stream contents. The test driver will ensure that all scenarios produce
+ * the same output (modulo allowable differences in ordering).
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public enum LongStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
+
+ STREAM_FOR_EACH(false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
+ LongStream s = m.apply(source);
+ if (s.isParallel()) {
+ s = s.sequential();
+ }
+ s.forEach(b);
+ }
+ },
+
+ STREAM_TO_ARRAY(false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
+ for (long t : m.apply(source).toArray()) {
+ b.accept(t);
+ }
+ }
+ },
+
+ STREAM_ITERATOR(false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
+ for (PrimitiveIterator.OfLong seqIter = m.apply(source).iterator(); seqIter.hasNext(); )
+ b.accept(seqIter.nextLong());
+ }
+ },
+
+ // Wrap as stream, and spliterate then iterate in pull mode
+ STREAM_SPLITERATOR(false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
+ for (Spliterator.OfLong spl = m.apply(source).spliterator(); spl.tryAdvance(b); ) {
+ }
+ }
+ },
+
+ // Wrap as stream, spliterate, then split a few times mixing advances with forEach
+ STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
+ SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(source).spliterator());
+ }
+ },
+
+ // Wrap as stream, and spliterate then iterate in pull mode
+ STREAM_SPLITERATOR_FOREACH(false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
+ m.apply(source).spliterator().forEachRemaining(b);
+ }
+ },
+
+ PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
+ m.apply(source).sequential().forEach(b);
+ }
+ },
+
+ // Wrap as parallel stream + forEachOrdered
+ PAR_STREAM_FOR_EACH_ORDERED(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
+ // @@@ Want to explicitly select ordered equalator
+ m.apply(source).forEachOrdered(b);
+ }
+ },
+
+ // Wrap as stream, and spliterate then iterate sequentially
+ PAR_STREAM_SPLITERATOR(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
+ for (Spliterator.OfLong spl = m.apply(source).spliterator(); spl.tryAdvance(b); ) {
+ }
+ }
+ },
+
+ // Wrap as stream, and spliterate then iterate sequentially
+ PAR_STREAM_SPLITERATOR_FOREACH(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
+ m.apply(source).spliterator().forEachRemaining(b);
+ }
+ },
+
+ PAR_STREAM_TO_ARRAY(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
+ for (long t : m.apply(source).toArray())
+ b.accept(t);
+ }
+ },
+
+ // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
+ PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
+ LongStream s = m.apply(source);
+ Spliterator.OfLong sp = s.spliterator();
+ LongStream ss = StreamSupport.longStream(() -> sp,
+ StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
+ | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED), true);
+ for (long t : ss.toArray())
+ b.accept(t);
+ }
+ },
+
+ PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
+ S_IN pipe1 = (S_IN) OpTestCase.chain(source,
+ new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+ LongStream pipe2 = m.apply(pipe1);
+
+ for (long t : pipe2.toArray())
+ b.accept(t);
+ }
+ },
+
+ // Wrap as parallel stream + forEach synchronizing
+ PAR_STREAM_FOR_EACH(true, false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
+ m.apply(source).forEach(e -> {
+ synchronized (data) {
+ b.accept(e);
+ }
+ });
+ }
+ },
+
+ // Wrap as parallel stream + forEach synchronizing and clear SIZED flag
+ PAR_STREAM_FOR_EACH_CLEAR_SIZED(true, false) {
+ <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
+ S_IN pipe1 = (S_IN) OpTestCase.chain(source,
+ new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+ m.apply(pipe1).forEach(e -> {
+ synchronized (data) {
+ b.accept(e);
+ }
+ });
+ }
+ },
+ ;
+
+ // The set of scenarios that clean the SIZED flag
+ public static final Set<LongStreamTestScenario> CLEAR_SIZED_SCENARIOS = Collections.unmodifiableSet(
+ EnumSet.of(PAR_STREAM_TO_ARRAY_CLEAR_SIZED, PAR_STREAM_FOR_EACH_CLEAR_SIZED));
+
+ private boolean isParallel;
+
+ private final boolean isOrdered;
+
+ LongStreamTestScenario(boolean isParallel) {
+ this(isParallel, true);
+ }
+
+ LongStreamTestScenario(boolean isParallel, boolean isOrdered) {
+ this.isParallel = isParallel;
+ this.isOrdered = isOrdered;
+ }
+
+ public StreamShape getShape() {
+ return StreamShape.LONG_VALUE;
+ }
+
+ public boolean isParallel() {
+ return isParallel;
+ }
+
+ public boolean isOrdered() {
+ return isOrdered;
+ }
+
+ public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+ void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
+ try (S_IN source = getStream(data)) {
+ run(data, source, (LongConsumer) b, (Function<S_IN, LongStream>) m);
+ }
+ }
+
+ abstract <T, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/OpTestCase.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,682 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+import org.testng.annotations.Test;
+
+/**
+ * Base class for streams test cases. Provides 'exercise' methods for taking
+ * lambdas that construct and modify streams, and evaluates them in different
+ * ways and asserts that they produce equivalent results.
+ */
+@Test
+public abstract class OpTestCase extends LoggingTestCase {
+
+ private final Map<StreamShape, Set<? extends BaseStreamTestScenario>> testScenarios;
+
+ protected OpTestCase() {
+ testScenarios = new EnumMap<>(StreamShape.class);
+ testScenarios.put(StreamShape.REFERENCE, Collections.unmodifiableSet(EnumSet.allOf(StreamTestScenario.class)));
+ testScenarios.put(StreamShape.INT_VALUE, Collections.unmodifiableSet(EnumSet.allOf(IntStreamTestScenario.class)));
+ testScenarios.put(StreamShape.LONG_VALUE, Collections.unmodifiableSet(EnumSet.allOf(LongStreamTestScenario.class)));
+ testScenarios.put(StreamShape.DOUBLE_VALUE, Collections.unmodifiableSet(EnumSet.allOf(DoubleStreamTestScenario.class)));
+ }
+
+ @SuppressWarnings("rawtypes")
+ public static int getStreamFlags(BaseStream s) {
+ return ((AbstractPipeline) s).getStreamFlags();
+ }
+
+ /**
+ * An asserter for results produced when exercising of stream or terminal
+ * tests.
+ *
+ * @param <R> the type of result to assert on
+ */
+ public interface ResultAsserter<R> {
+ /**
+ * Assert a result produced when exercising of stream or terminal
+ * test.
+ *
+ * @param actual the actual result
+ * @param expected the expected result
+ * @param isOrdered true if the pipeline is ordered
+ * @param isParallel true if the pipeline is parallel
+ */
+ void assertResult(R actual, R expected, boolean isOrdered, boolean isParallel);
+ }
+
+ // Exercise stream operations
+
+ public interface BaseStreamTestScenario {
+ StreamShape getShape();
+
+ boolean isParallel();
+
+ boolean isOrdered();
+
+ default <T, S_IN extends BaseStream<T, S_IN>>
+ S_IN getStream(TestData<T, S_IN> data) {
+ return isParallel()
+ ? data.parallelStream()
+ : data.stream();
+ }
+
+ <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+ void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m);
+ }
+
+ protected <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+ Collection<U> exerciseOps(TestData<T, S_IN> data, Function<S_IN, S_OUT> m) {
+ return withData(data).stream(m).exercise();
+ }
+
+ // Run multiple versions of exercise(), returning the result of the first, and asserting that others return the same result
+ // If the first version is s -> s.foo(), can be used with s -> s.mapToInt(i -> i).foo().mapToObj(i -> i) to test all shape variants
+ @SafeVarargs
+ protected final<T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+ Collection<U> exerciseOpsMulti(TestData<T, S_IN> data,
+ Function<S_IN, S_OUT>... ms) {
+ Collection<U> result = null;
+ for (Function<S_IN, S_OUT> m : ms) {
+ if (result == null)
+ result = withData(data).stream(m).exercise();
+ else {
+ Collection<U> r2 = withData(data).stream(m).exercise();
+ assertEquals(result, r2);
+ }
+ }
+ return result;
+ }
+
+ // Run multiple versions of exercise() for an Integer stream, returning the result of the first, and asserting that others return the same result
+ // Automates the conversion between Stream<Integer> and {Int,Long,Double}Stream and back, so client sites look like you are passing the same
+ // lambda four times, but in fact they are four different lambdas since they are transforming four different kinds of streams
+ protected final
+ Collection<Integer> exerciseOpsInt(TestData.OfRef<Integer> data,
+ Function<Stream<Integer>, Stream<Integer>> mRef,
+ Function<IntStream, IntStream> mInt,
+ Function<LongStream, LongStream> mLong,
+ Function<DoubleStream, DoubleStream> mDouble) {
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ Function<Stream<Integer>, Stream<Integer>>[] ms = new Function[4];
+ ms[0] = mRef;
+ ms[1] = s -> mInt.apply(s.mapToInt(e -> e)).mapToObj(e -> e);
+ ms[2] = s -> mLong.apply(s.mapToLong(e -> e)).mapToObj(e -> (int) e);
+ ms[3] = s -> mDouble.apply(s.mapToDouble(e -> e)).mapToObj(e -> (int) e);
+ return exerciseOpsMulti(data, ms);
+ }
+
+ // Run multiple versions of exercise() with multiple terminal operations for all kinds of stream, , and asserting against the expected result
+ // If the first version is s -> s.foo(), can be used with s -> s.mapToInt(i -> i).foo().mapToObj(i -> i) to test all shape variants
+ protected final<T, U, R, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+ void exerciseTerminalOpsMulti(TestData<T, S_IN> data,
+ R expected,
+ Map<String, Function<S_IN, S_OUT>> streams,
+ Map<String, Function<S_OUT, R>> terminals) {
+ for (Map.Entry<String, Function<S_IN, S_OUT>> se : streams.entrySet()) {
+ setContext("Intermediate stream", se.getKey());
+ for (Map.Entry<String, Function<S_OUT, R>> te : terminals.entrySet()) {
+ setContext("Terminal stream", te.getKey());
+ withData(data)
+ .terminal(se.getValue(), te.getValue())
+ .expectedResult(expected)
+ .exercise();
+
+ }
+ }
+ }
+
+ // Run multiple versions of exercise() with multiple terminal operation for all kinds of stream, and asserting against the expected result
+ // Automates the conversion between Stream<Integer> and {Int,Long,Double}Stream and back, so client sites look like you are passing the same
+ // lambda four times, but in fact they are four different lambdas since they are transforming four different kinds of streams
+ protected final
+ void exerciseTerminalOpsInt(TestData<Integer, Stream<Integer>> data,
+ Collection<Integer> expected,
+ String desc,
+ Function<Stream<Integer>, Stream<Integer>> mRef,
+ Function<IntStream, IntStream> mInt,
+ Function<LongStream, LongStream> mLong,
+ Function<DoubleStream, DoubleStream> mDouble,
+ Map<String, Function<Stream<Integer>, Collection<Integer>>> terminals) {
+
+ Map<String, Function<Stream<Integer>, Stream<Integer>>> m = new HashMap<>();
+ m.put("Ref " + desc, mRef);
+ m.put("Int " + desc, s -> mInt.apply(s.mapToInt(e -> e)).mapToObj(e -> e));
+ m.put("Long " + desc, s -> mLong.apply(s.mapToLong(e -> e)).mapToObj(e -> (int) e));
+ m.put("Double " + desc, s -> mDouble.apply(s.mapToDouble(e -> e)).mapToObj(e -> (int) e));
+
+ exerciseTerminalOpsMulti(data, expected, m, terminals);
+ }
+
+
+ protected <T, U, S_OUT extends BaseStream<U, S_OUT>>
+ Collection<U> exerciseOps(Collection<T> data, Function<Stream<T>, S_OUT> m) {
+ TestData.OfRef<T> data1 = TestData.Factory.ofCollection("Collection of type " + data.getClass().getName(), data);
+ return withData(data1).stream(m).exercise();
+ }
+
+ protected <T, U, S_OUT extends BaseStream<U, S_OUT>, I extends Iterable<U>>
+ Collection<U> exerciseOps(Collection<T> data, Function<Stream<T>, S_OUT> m, I expected) {
+ TestData.OfRef<T> data1 = TestData.Factory.ofCollection("Collection of type " + data.getClass().getName(), data);
+ return withData(data1).stream(m).expectedResult(expected).exercise();
+ }
+
+ @SuppressWarnings("unchecked")
+ protected <U, S_OUT extends BaseStream<U, S_OUT>>
+ Collection<U> exerciseOps(int[] data, Function<IntStream, S_OUT> m) {
+ return withData(TestData.Factory.ofArray("int array", data)).stream(m).exercise();
+ }
+
+ protected Collection<Integer> exerciseOps(int[] data, Function<IntStream, IntStream> m, int[] expected) {
+ TestData.OfInt data1 = TestData.Factory.ofArray("int array", data);
+ return withData(data1).stream(m).expectedResult(expected).exercise();
+ }
+
+ protected <T, S_IN extends BaseStream<T, S_IN>> DataStreamBuilder<T, S_IN> withData(TestData<T, S_IN> data) {
+ Objects.requireNonNull(data);
+ return new DataStreamBuilder<>(data);
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public class DataStreamBuilder<T, S_IN extends BaseStream<T, S_IN>> {
+ final TestData<T, S_IN> data;
+
+ private DataStreamBuilder(TestData<T, S_IN> data) {
+ this.data = Objects.requireNonNull(data);
+ }
+
+ public <U, S_OUT extends BaseStream<U, S_OUT>>
+ ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> ops(IntermediateTestOp... ops) {
+ return new ExerciseDataStreamBuilder<>(data, (S_IN s) -> (S_OUT) chain(s, ops));
+ }
+
+ public <U, S_OUT extends BaseStream<U, S_OUT>> ExerciseDataStreamBuilder<T, U, S_IN, S_OUT>
+ stream(Function<S_IN, S_OUT> m) {
+ return new ExerciseDataStreamBuilder<>(data, m);
+ }
+
+ public <U, S_OUT extends BaseStream<U, S_OUT>> ExerciseDataStreamBuilder<T, U, S_IN, S_OUT>
+ stream(Function<S_IN, S_OUT> m, IntermediateTestOp<U, U> additionalOp) {
+ return new ExerciseDataStreamBuilder<>(data, s -> (S_OUT) chain(m.apply(s), additionalOp));
+ }
+
+ public <R> ExerciseDataTerminalBuilder<T, T, R, S_IN, S_IN>
+ terminal(Function<S_IN, R> terminalF) {
+ return new ExerciseDataTerminalBuilder<>(data, s -> s, terminalF);
+ }
+
+ public <U, R, S_OUT extends BaseStream<U, S_OUT>> ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT>
+ terminal(Function<S_IN, S_OUT> streamF, Function<S_OUT, R> terminalF) {
+ return new ExerciseDataTerminalBuilder<>(data, streamF, terminalF);
+ }
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public class ExerciseDataStreamBuilder<T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>> {
+ final TestData<T, S_IN> data;
+ final Function<S_IN, S_OUT> m;
+ final StreamShape shape;
+
+ Set<BaseStreamTestScenario> testSet = new HashSet<>();
+
+ Collection<U> refResult;
+
+ Consumer<TestData<T, S_IN>> before = LambdaTestHelpers.bEmpty;
+
+ Consumer<TestData<T, S_IN>> after = LambdaTestHelpers.bEmpty;
+
+ ResultAsserter<Iterable<U>> resultAsserter = (act, exp, ord, par) -> {
+ if (par & !ord) {
+ LambdaTestHelpers.assertContentsUnordered(act, exp);
+ }
+ else {
+ LambdaTestHelpers.assertContentsEqual(act, exp);
+ }
+ };
+
+ private ExerciseDataStreamBuilder(TestData<T, S_IN> data, Function<S_IN, S_OUT> m) {
+ this.data = data;
+
+ this.m = Objects.requireNonNull(m);
+
+ this.shape = ((AbstractPipeline<?, U, ?>) m.apply(data.stream())).getOutputShape();
+
+ // Have to initiate from the output shape of the last stream
+ // This means the stream mapper is required first rather than last
+ testSet.addAll(testScenarios.get(shape));
+ }
+
+ //
+
+ public <I extends Iterable<U>> ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(I expectedResult) {
+ List<U> l = new ArrayList<>();
+ expectedResult.forEach(l::add);
+ refResult = l;
+ return this;
+ }
+
+ public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(int[] expectedResult) {
+ List l = new ArrayList();
+ for (int anExpectedResult : expectedResult) {
+ l.add(anExpectedResult);
+ }
+ refResult = l;
+ return this;
+ }
+
+ public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(long[] expectedResult) {
+ List l = new ArrayList();
+ for (long anExpectedResult : expectedResult) {
+ l.add(anExpectedResult);
+ }
+ refResult = l;
+ return this;
+ }
+
+ public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(double[] expectedResult) {
+ List l = new ArrayList();
+ for (double anExpectedResult : expectedResult) {
+ l.add(anExpectedResult);
+ }
+ refResult = l;
+ return this;
+ }
+
+ public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> before(Consumer<TestData<T, S_IN>> before) {
+ this.before = Objects.requireNonNull(before);
+ return this;
+ }
+
+ public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> after(Consumer<TestData<T, S_IN>> after) {
+ this.after = Objects.requireNonNull(after);
+ return this;
+ }
+
+ public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> without(BaseStreamTestScenario... tests) {
+ return without(Arrays.asList(tests));
+ }
+
+ public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> without(Collection<? extends BaseStreamTestScenario> tests) {
+ for (BaseStreamTestScenario ts : tests) {
+ if (ts.getShape() == shape) {
+ testSet.remove(ts);
+ }
+ }
+
+ if (testSet.isEmpty()) {
+ throw new IllegalStateException("Test scenario set is empty");
+ }
+
+ return this;
+ }
+
+ public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> with(BaseStreamTestScenario... tests) {
+ return with(Arrays.asList(tests));
+ }
+
+ public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> with(Collection<? extends BaseStreamTestScenario> tests) {
+ testSet = new HashSet<>();
+
+ for (BaseStreamTestScenario ts : tests) {
+ if (ts.getShape() == shape) {
+ testSet.add(ts);
+ }
+ }
+
+ if (testSet.isEmpty()) {
+ throw new IllegalStateException("Test scenario set is empty");
+ }
+
+ return this;
+ }
+
+ public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> resultAsserter(ResultAsserter<Iterable<U>> resultAsserter) {
+ this.resultAsserter = resultAsserter;
+ return this;
+ }
+
+ // Build method
+
+ public Collection<U> exercise() {
+ final boolean isStreamOrdered;
+ if (refResult == null) {
+ // Induce the reference result
+ before.accept(data);
+ try (S_OUT sOut = m.apply(data.stream())) {
+ isStreamOrdered = StreamOpFlag.ORDERED.isKnown(((AbstractPipeline) sOut).getStreamFlags());
+ Node<U> refNodeResult = ((AbstractPipeline<?, U, ?>) sOut).evaluateToArrayNode(size -> (U[]) new Object[size]);
+ refResult = LambdaTestHelpers.toBoxedList(refNodeResult.spliterator());
+ }
+ after.accept(data);
+ }
+ else {
+ try (S_OUT sOut = m.apply(data.stream())) {
+ isStreamOrdered = StreamOpFlag.ORDERED.isKnown(((AbstractPipeline) sOut).getStreamFlags());
+ }
+ }
+
+ List<Error> errors = new ArrayList<>();
+ for (BaseStreamTestScenario test : testSet) {
+ try {
+ before.accept(data);
+
+ List<U> result = new ArrayList<>();
+ test.run(data, LambdaTestHelpers.<U>toBoxingConsumer(result::add), m);
+
+ Runnable asserter = () -> resultAsserter.assertResult(result, refResult, isStreamOrdered && test.isOrdered(), test.isParallel());
+
+ if (refResult.size() > 1000) {
+ LambdaTestHelpers.launderAssertion(
+ asserter,
+ () -> String.format("%n%s: [actual size=%d] != [expected size=%d]", test, result.size(), refResult.size()));
+ }
+ else {
+ LambdaTestHelpers.launderAssertion(
+ asserter,
+ () -> String.format("%n%s: [actual] %s != [expected] %s", test, result, refResult));
+ }
+
+ after.accept(data);
+ } catch (Throwable t) {
+ errors.add(new Error(String.format("%s: %s", test, t), t));
+ }
+ }
+
+ if (!errors.isEmpty()) {
+ StringBuilder sb = new StringBuilder();
+ int i = 1;
+ for (Error t : errors) {
+ sb.append(i++).append(": ");
+ if (t instanceof AssertionError) {
+ sb.append(t).append("\n");
+ }
+ else {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+
+ t.getCause().printStackTrace(pw);
+ pw.flush();
+ sb.append(t).append("\n").append(sw);
+ }
+ }
+ sb.append("--");
+
+ fail(String.format("%d failure(s) for test data: %s\n%s", i - 1, data.toString(), sb));
+ }
+
+ return refResult;
+ }
+ }
+
+ // Exercise terminal operations
+
+ interface BaseTerminalTestScenario<U, R, S_OUT extends BaseStream<U, S_OUT>> {
+ boolean requiresSingleStageSource();
+
+ boolean requiresParallelSource();
+
+ default R run(Function<S_OUT, R> terminalF, S_OUT source, StreamShape shape) {
+ return terminalF.apply(source);
+ }
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ enum TerminalTestScenario implements BaseTerminalTestScenario {
+ SINGLE_SEQUENTIAL(true, false),
+
+ SINGLE_SEQUENTIAL_SHORT_CIRCUIT(true, false) {
+ @Override
+ public Object run(Function terminalF, BaseStream source, StreamShape shape) {
+ source = (BaseStream) chain(source, new ShortCircuitOp(shape));
+ return terminalF.apply(source);
+ }
+ },
+
+ SINGLE_PARALLEL(true, true),
+
+ ALL_SEQUENTIAL(false, false),
+
+ ALL_SEQUENTIAL_SHORT_CIRCUIT(false, false) {
+ @Override
+ public Object run(Function terminalF, BaseStream source, StreamShape shape) {
+ source = (BaseStream) chain(source, new ShortCircuitOp(shape));
+ return terminalF.apply(source);
+ }
+ },
+
+ ALL_PARALLEL(false, true),
+
+ ALL_PARALLEL_SEQUENTIAL(false, false) {
+ @Override
+ public Object run(Function terminalF, BaseStream source, StreamShape shape) {
+ return terminalF.apply(source.sequential());
+ }
+ },
+ ;
+
+ private final boolean requiresSingleStageSource;
+ private final boolean isParallel;
+
+ TerminalTestScenario(boolean requiresSingleStageSource, boolean isParallel) {
+ this.requiresSingleStageSource = requiresSingleStageSource;
+ this.isParallel = isParallel;
+ }
+
+ @Override
+ public boolean requiresSingleStageSource() {
+ return requiresSingleStageSource;
+ }
+
+ @Override
+ public boolean requiresParallelSource() {
+ return isParallel;
+ }
+
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public class ExerciseDataTerminalBuilder<T, U, R, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>> {
+ final TestData<T, S_IN> data;
+ final Function<S_IN, S_OUT> streamF;
+ final Function<S_OUT, R> terminalF;
+
+ R refResult;
+
+ ResultAsserter<R> resultAsserter = (act, exp, ord, par) -> LambdaTestHelpers.assertContentsEqual(act, exp);
+
+ private ExerciseDataTerminalBuilder(TestData<T, S_IN> data, Function<S_IN, S_OUT> streamF, Function<S_OUT, R> terminalF) {
+ this.data = data;
+ this.streamF = Objects.requireNonNull(streamF);
+ this.terminalF = Objects.requireNonNull(terminalF);
+ }
+
+ //
+
+ public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> expectedResult(R expectedResult) {
+ this.refResult = expectedResult;
+ return this;
+ }
+
+ public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> equalator(BiConsumer<R, R> equalityAsserter) {
+ resultAsserter = (act, exp, ord, par) -> equalityAsserter.accept(act, exp);
+ return this;
+ }
+
+ public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> resultAsserter(ResultAsserter<R> resultAsserter) {
+ this.resultAsserter = resultAsserter;
+ return this;
+ }
+
+ // Build method
+
+ public R exercise() {
+ boolean isOrdered;
+ StreamShape shape;
+ Node<U> node;
+ try (S_OUT out = streamF.apply(data.stream()).sequential()) {
+ AbstractPipeline ap = (AbstractPipeline) out;
+ isOrdered = StreamOpFlag.ORDERED.isKnown(ap.getStreamFlags());
+ shape = ap.getOutputShape();
+ // Sequentially collect the output that will be input to the terminal op
+ node = ap.evaluateToArrayNode(size -> (U[]) new Object[size]);
+ }
+
+ EnumSet<TerminalTestScenario> tests = EnumSet.allOf(TerminalTestScenario.class);
+ if (refResult == null) {
+ // Induce the reference result
+ S_OUT source = (S_OUT) createPipeline(shape, node.spliterator(),
+ StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED,
+ false);
+
+ refResult = (R) TerminalTestScenario.SINGLE_SEQUENTIAL.run(terminalF, source, shape);
+ tests.remove(TerminalTestScenario.SINGLE_SEQUENTIAL);
+ }
+
+ for (BaseTerminalTestScenario test : tests) {
+ S_OUT source;
+ if (test.requiresSingleStageSource()) {
+ source = (S_OUT) createPipeline(shape, node.spliterator(),
+ StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED,
+ test.requiresParallelSource());
+ }
+ else {
+ source = streamF.apply(test.requiresParallelSource()
+ ? data.parallelStream() : data.stream());
+ }
+
+ R result;
+ try (source) {
+ result = (R) test.run(terminalF, source, shape);
+ }
+ LambdaTestHelpers.launderAssertion(
+ () -> resultAsserter.assertResult(result, refResult, isOrdered, test.requiresParallelSource()),
+ () -> String.format("%s: %s != %s", test, refResult, result));
+ }
+
+ return refResult;
+ }
+
+ AbstractPipeline createPipeline(StreamShape shape, Spliterator s, int flags, boolean parallel) {
+ switch (shape) {
+ case REFERENCE: return new ReferencePipeline.Head<>(s, flags, parallel);
+ case INT_VALUE: return new IntPipeline.Head(s, flags, parallel);
+ case LONG_VALUE: return new LongPipeline.Head(s, flags, parallel);
+ case DOUBLE_VALUE: return new DoublePipeline.Head(s, flags, parallel);
+ default: throw new IllegalStateException("Unknown shape: " + shape);
+ }
+ }
+ }
+
+ protected <T, R> R exerciseTerminalOps(Collection<T> data, Function<Stream<T>, R> m, R expected) {
+ TestData.OfRef<T> data1
+ = TestData.Factory.ofCollection("Collection of type " + data.getClass().getName(), data);
+ return withData(data1).terminal(m).expectedResult(expected).exercise();
+ }
+
+ protected <T, R, S_IN extends BaseStream<T, S_IN>> R
+ exerciseTerminalOps(TestData<T, S_IN> data,
+ Function<S_IN, R> terminalF) {
+ return withData(data).terminal(terminalF).exercise();
+ }
+
+ protected <T, U, R, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>> R
+ exerciseTerminalOps(TestData<T, S_IN> data,
+ Function<S_IN, S_OUT> streamF,
+ Function<S_OUT, R> terminalF) {
+ return withData(data).terminal(streamF, terminalF).exercise();
+ }
+
+ //
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ private static <T> AbstractPipeline<?, T, ?> chain(AbstractPipeline upstream, IntermediateTestOp<?, T> op) {
+ return (AbstractPipeline<?, T, ?>) IntermediateTestOp.chain(upstream, op);
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ private static AbstractPipeline<?, ?, ?> chain(AbstractPipeline pipe, IntermediateTestOp... ops) {
+ for (IntermediateTestOp op : ops)
+ pipe = chain(pipe, op);
+ return pipe;
+ }
+
+ @SuppressWarnings("rawtypes")
+ private static <T> AbstractPipeline<?, T, ?> chain(BaseStream pipe, IntermediateTestOp<?, T> op) {
+ return chain((AbstractPipeline) pipe, op);
+ }
+
+ @SuppressWarnings("rawtypes")
+ public static AbstractPipeline<?, ?, ?> chain(BaseStream pipe, IntermediateTestOp... ops) {
+ return chain((AbstractPipeline) pipe, ops);
+ }
+
+ // Test data
+
+ static class ShortCircuitOp<T> implements StatelessTestOp<T,T> {
+ private final StreamShape shape;
+
+ ShortCircuitOp(StreamShape shape) {
+ this.shape = shape;
+ }
+
+ @Override
+ public Sink<T> opWrapSink(int flags, boolean parallel, Sink<T> sink) {
+ return sink;
+ }
+
+ @Override
+ public int opGetFlags() {
+ return StreamOpFlag.IS_SHORT_CIRCUIT;
+ }
+
+ @Override
+ public StreamShape outputShape() {
+ return shape;
+ }
+
+ @Override
+ public StreamShape inputShape() {
+ return shape;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/SpliteratorTestHelper.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,715 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Spliterator;
+import java.util.function.*;
+
+import static org.testng.Assert.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+/**
+ * Assertion methods for spliterators, to be called from other tests
+ */
+public class SpliteratorTestHelper {
+
+ public interface ContentAsserter<T> {
+ void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered);
+ }
+
+ private static ContentAsserter<Object> DEFAULT_CONTENT_ASSERTER
+ = SpliteratorTestHelper::assertContents;
+
+ @SuppressWarnings("unchecked")
+ private static <T> ContentAsserter<T> defaultContentAsserter() {
+ return (ContentAsserter<T>) DEFAULT_CONTENT_ASSERTER;
+ }
+
+ public static void testSpliterator(Supplier<Spliterator<Integer>> supplier) {
+ testSpliterator(supplier, defaultContentAsserter());
+ }
+
+ public static void testSpliterator(Supplier<Spliterator<Integer>> supplier,
+ ContentAsserter<Integer> asserter) {
+ testSpliterator(supplier, (Consumer<Integer> b) -> b, asserter);
+ }
+
+ public static void testIntSpliterator(Supplier<Spliterator.OfInt> supplier) {
+ testIntSpliterator(supplier, defaultContentAsserter());
+ }
+
+ public static void testIntSpliterator(Supplier<Spliterator.OfInt> supplier,
+ ContentAsserter<Integer> asserter) {
+ class BoxingAdapter implements Consumer<Integer>, IntConsumer {
+ private final Consumer<Integer> b;
+
+ BoxingAdapter(Consumer<Integer> b) {
+ this.b = b;
+ }
+
+ @Override
+ public void accept(Integer value) {
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public void accept(int value) {
+ b.accept(value);
+ }
+ }
+
+ testSpliterator(supplier, BoxingAdapter::new, asserter);
+ }
+
+ public static void testLongSpliterator(Supplier<Spliterator.OfLong> supplier) {
+ testLongSpliterator(supplier, defaultContentAsserter());
+ }
+
+ public static void testLongSpliterator(Supplier<Spliterator.OfLong> supplier,
+ ContentAsserter<Long> asserter) {
+ class BoxingAdapter implements Consumer<Long>, LongConsumer {
+ private final Consumer<Long> b;
+
+ BoxingAdapter(Consumer<Long> b) {
+ this.b = b;
+ }
+
+ @Override
+ public void accept(Long value) {
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public void accept(long value) {
+ b.accept(value);
+ }
+ }
+
+ testSpliterator(supplier, BoxingAdapter::new, asserter);
+ }
+
+ public static void testDoubleSpliterator(Supplier<Spliterator.OfDouble> supplier) {
+ testDoubleSpliterator(supplier, defaultContentAsserter());
+ }
+
+ public static void testDoubleSpliterator(Supplier<Spliterator.OfDouble> supplier,
+ ContentAsserter<Double> asserter) {
+ class BoxingAdapter implements Consumer<Double>, DoubleConsumer {
+ private final Consumer<Double> b;
+
+ BoxingAdapter(Consumer<Double> b) {
+ this.b = b;
+ }
+
+ @Override
+ public void accept(Double value) {
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public void accept(double value) {
+ b.accept(value);
+ }
+ }
+
+ testSpliterator(supplier, BoxingAdapter::new, asserter);
+ }
+
+ static <T, S extends Spliterator<T>> void testSpliterator(Supplier<S> supplier,
+ UnaryOperator<Consumer<T>> boxingAdapter,
+ ContentAsserter<T> asserter) {
+ ArrayList<T> fromForEach = new ArrayList<>();
+ Spliterator<T> spliterator = supplier.get();
+ Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add);
+ spliterator.forEachRemaining(addToFromForEach);
+
+ Collection<T> exp = Collections.unmodifiableList(fromForEach);
+
+ testNullPointerException(supplier);
+ testForEach(exp, supplier, boxingAdapter, asserter);
+ testTryAdvance(exp, supplier, boxingAdapter, asserter);
+ testMixedTryAdvanceForEach(exp, supplier, boxingAdapter, asserter);
+ testMixedTraverseAndSplit(exp, supplier, boxingAdapter, asserter);
+ testSplitAfterFullTraversal(supplier, boxingAdapter);
+ testSplitOnce(exp, supplier, boxingAdapter, asserter);
+ testSplitSixDeep(exp, supplier, boxingAdapter, asserter);
+ testSplitUntilNull(exp, supplier, boxingAdapter, asserter);
+ }
+
+ //
+
+ private static <T, S extends Spliterator<T>> void testNullPointerException(Supplier<S> s) {
+ S sp = s.get();
+ // Have to check instances and use casts to avoid tripwire messages and
+ // directly test the primitive methods
+ if (sp instanceof Spliterator.OfInt) {
+ Spliterator.OfInt psp = (Spliterator.OfInt) sp;
+ executeAndCatch(NullPointerException.class, () -> psp.forEachRemaining((IntConsumer) null));
+ executeAndCatch(NullPointerException.class, () -> psp.tryAdvance((IntConsumer) null));
+ }
+ else if (sp instanceof Spliterator.OfLong) {
+ Spliterator.OfLong psp = (Spliterator.OfLong) sp;
+ executeAndCatch(NullPointerException.class, () -> psp.forEachRemaining((LongConsumer) null));
+ executeAndCatch(NullPointerException.class, () -> psp.tryAdvance((LongConsumer) null));
+ }
+ else if (sp instanceof Spliterator.OfDouble) {
+ Spliterator.OfDouble psp = (Spliterator.OfDouble) sp;
+ executeAndCatch(NullPointerException.class, () -> psp.forEachRemaining((DoubleConsumer) null));
+ executeAndCatch(NullPointerException.class, () -> psp.tryAdvance((DoubleConsumer) null));
+ }
+ else {
+ executeAndCatch(NullPointerException.class, () -> sp.forEachRemaining(null));
+ executeAndCatch(NullPointerException.class, () -> sp.tryAdvance(null));
+ }
+ }
+
+ private static <T, S extends Spliterator<T>> void testForEach(
+ Collection<T> exp,
+ Supplier<S> supplier,
+ UnaryOperator<Consumer<T>> boxingAdapter,
+ ContentAsserter<T> asserter) {
+ S spliterator = supplier.get();
+ long sizeIfKnown = spliterator.getExactSizeIfKnown();
+ boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+ ArrayList<T> fromForEach = new ArrayList<>();
+ spliterator = supplier.get();
+ Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add);
+ spliterator.forEachRemaining(addToFromForEach);
+
+ // Assert that forEach now produces no elements
+ spliterator.forEachRemaining(boxingAdapter.apply(
+ e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
+ // Assert that tryAdvance now produce no elements
+ spliterator.tryAdvance(boxingAdapter.apply(
+ e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
+
+ // assert that size, tryAdvance, and forEach are consistent
+ if (sizeIfKnown >= 0) {
+ assertEquals(sizeIfKnown, exp.size());
+ }
+ assertEquals(fromForEach.size(), exp.size());
+
+ asserter.assertContents(fromForEach, exp, isOrdered);
+ }
+
+ private static <T, S extends Spliterator<T>> void testTryAdvance(
+ Collection<T> exp,
+ Supplier<S> supplier,
+ UnaryOperator<Consumer<T>> boxingAdapter,
+ ContentAsserter<T> asserter) {
+ S spliterator = supplier.get();
+ long sizeIfKnown = spliterator.getExactSizeIfKnown();
+ boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+ spliterator = supplier.get();
+ ArrayList<T> fromTryAdvance = new ArrayList<>();
+ Consumer<T> addToFromTryAdvance = boxingAdapter.apply(fromTryAdvance::add);
+ while (spliterator.tryAdvance(addToFromTryAdvance)) { }
+
+ // Assert that forEach now produces no elements
+ spliterator.forEachRemaining(boxingAdapter.apply(
+ e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
+ // Assert that tryAdvance now produce no elements
+ spliterator.tryAdvance(boxingAdapter.apply(
+ e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
+
+ // assert that size, tryAdvance, and forEach are consistent
+ if (sizeIfKnown >= 0) {
+ assertEquals(sizeIfKnown, exp.size());
+ }
+ assertEquals(fromTryAdvance.size(), exp.size());
+
+ asserter.assertContents(fromTryAdvance, exp, isOrdered);
+ }
+
+ private static <T, S extends Spliterator<T>> void testMixedTryAdvanceForEach(
+ Collection<T> exp,
+ Supplier<S> supplier,
+ UnaryOperator<Consumer<T>> boxingAdapter,
+ ContentAsserter<T> asserter) {
+ S spliterator = supplier.get();
+ long sizeIfKnown = spliterator.getExactSizeIfKnown();
+ boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+ // tryAdvance first few elements, then forEach rest
+ ArrayList<T> dest = new ArrayList<>();
+ spliterator = supplier.get();
+ Consumer<T> addToDest = boxingAdapter.apply(dest::add);
+ for (int i = 0; i < 10 && spliterator.tryAdvance(addToDest); i++) { }
+ spliterator.forEachRemaining(addToDest);
+
+ // Assert that forEach now produces no elements
+ spliterator.forEachRemaining(boxingAdapter.apply(
+ e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
+ // Assert that tryAdvance now produce no elements
+ spliterator.tryAdvance(boxingAdapter.apply(
+ e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
+
+ if (sizeIfKnown >= 0) {
+ assertEquals(sizeIfKnown, dest.size());
+ }
+ assertEquals(dest.size(), exp.size());
+
+ asserter.assertContents(dest, exp, isOrdered);
+ }
+
+ private static <T, S extends Spliterator<T>> void testMixedTraverseAndSplit(
+ Collection<T> exp,
+ Supplier<S> supplier,
+ UnaryOperator<Consumer<T>> boxingAdapter,
+ ContentAsserter<T> asserter) {
+ S spliterator = supplier.get();
+ long sizeIfKnown = spliterator.getExactSizeIfKnown();
+ boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+ // tryAdvance first few elements, then forEach rest
+ ArrayList<T> dest = new ArrayList<>();
+ spliterator = supplier.get();
+ Consumer<T> b = boxingAdapter.apply(dest::add);
+
+ Spliterator<T> spl1, spl2, spl3;
+ spliterator.tryAdvance(b);
+ spl2 = spliterator.trySplit();
+ if (spl2 != null) {
+ spl2.tryAdvance(b);
+ spl1 = spl2.trySplit();
+ if (spl1 != null) {
+ spl1.tryAdvance(b);
+ spl1.forEachRemaining(b);
+ }
+ spl2.tryAdvance(b);
+ spl2.forEachRemaining(b);
+ }
+ spliterator.tryAdvance(b);
+ spl3 = spliterator.trySplit();
+ if (spl3 != null) {
+ spl3.tryAdvance(b);
+ spl3.forEachRemaining(b);
+ }
+ spliterator.tryAdvance(b);
+ spliterator.forEachRemaining(b);
+
+ if (sizeIfKnown >= 0) {
+ assertEquals(sizeIfKnown, dest.size());
+ }
+ assertEquals(dest.size(), exp.size());
+
+ asserter.assertContents(dest, exp, isOrdered);
+ }
+
+ private static <T, S extends Spliterator<T>> void testSplitAfterFullTraversal(
+ Supplier<S> supplier,
+ UnaryOperator<Consumer<T>> boxingAdapter) {
+ // Full traversal using tryAdvance
+ Spliterator<T> spliterator = supplier.get();
+ while (spliterator.tryAdvance(boxingAdapter.apply(e -> { }))) { }
+ Spliterator<T> split = spliterator.trySplit();
+ assertNull(split);
+
+ // Full traversal using forEach
+ spliterator = supplier.get();
+ spliterator.forEachRemaining(boxingAdapter.apply(e -> { }));
+ split = spliterator.trySplit();
+ assertNull(split);
+
+ // Full traversal using tryAdvance then forEach
+ spliterator = supplier.get();
+ spliterator.tryAdvance(boxingAdapter.apply(e -> { }));
+ spliterator.forEachRemaining(boxingAdapter.apply(e -> { }));
+ split = spliterator.trySplit();
+ assertNull(split);
+ }
+
+ private static <T, S extends Spliterator<T>> void testSplitOnce(
+ Collection<T> exp,
+ Supplier<S> supplier,
+ UnaryOperator<Consumer<T>> boxingAdapter,
+ ContentAsserter<T> asserter) {
+ S spliterator = supplier.get();
+ long sizeIfKnown = spliterator.getExactSizeIfKnown();
+ boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+ ArrayList<T> fromSplit = new ArrayList<>();
+ Spliterator<T> s1 = supplier.get();
+ Spliterator<T> s2 = s1.trySplit();
+ long s1Size = s1.getExactSizeIfKnown();
+ long s2Size = (s2 != null) ? s2.getExactSizeIfKnown() : 0;
+ Consumer<T> addToFromSplit = boxingAdapter.apply(fromSplit::add);
+ if (s2 != null)
+ s2.forEachRemaining(addToFromSplit);
+ s1.forEachRemaining(addToFromSplit);
+
+ if (sizeIfKnown >= 0) {
+ assertEquals(sizeIfKnown, fromSplit.size());
+ if (s1Size >= 0 && s2Size >= 0)
+ assertEquals(sizeIfKnown, s1Size + s2Size);
+ }
+
+ asserter.assertContents(fromSplit, exp, isOrdered);
+ }
+
+ private static <T, S extends Spliterator<T>> void testSplitSixDeep(
+ Collection<T> exp,
+ Supplier<S> supplier,
+ UnaryOperator<Consumer<T>> boxingAdapter,
+ ContentAsserter<T> asserter) {
+ S spliterator = supplier.get();
+ boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+ for (int depth=0; depth < 6; depth++) {
+ List<T> dest = new ArrayList<>();
+ spliterator = supplier.get();
+
+ assertSpliterator(spliterator);
+
+ // verify splitting with forEach
+ splitSixDeepVisitor(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), false);
+ asserter.assertContents(dest, exp, isOrdered);
+
+ // verify splitting with tryAdvance
+ dest.clear();
+ spliterator = supplier.get();
+ splitSixDeepVisitor(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), true);
+ asserter.assertContents(dest, exp, isOrdered);
+ }
+ }
+
+ private static <T, S extends Spliterator<T>>
+ void splitSixDeepVisitor(int depth, int curLevel,
+ List<T> dest, S spliterator, UnaryOperator<Consumer<T>> boxingAdapter,
+ int rootCharacteristics, boolean useTryAdvance) {
+ if (curLevel < depth) {
+ long beforeSize = spliterator.getExactSizeIfKnown();
+ Spliterator<T> split = spliterator.trySplit();
+ if (split != null) {
+ assertSpliterator(split, rootCharacteristics);
+ assertSpliterator(spliterator, rootCharacteristics);
+
+ if ((rootCharacteristics & Spliterator.SUBSIZED) != 0 &&
+ (rootCharacteristics & Spliterator.SIZED) != 0) {
+ assertEquals(beforeSize, split.estimateSize() + spliterator.estimateSize());
+ }
+ splitSixDeepVisitor(depth, curLevel + 1, dest, split, boxingAdapter, rootCharacteristics, useTryAdvance);
+ }
+ splitSixDeepVisitor(depth, curLevel + 1, dest, spliterator, boxingAdapter, rootCharacteristics, useTryAdvance);
+ }
+ else {
+ long sizeIfKnown = spliterator.getExactSizeIfKnown();
+ if (useTryAdvance) {
+ Consumer<T> addToDest = boxingAdapter.apply(dest::add);
+ int count = 0;
+ while (spliterator.tryAdvance(addToDest)) {
+ ++count;
+ }
+
+ if (sizeIfKnown >= 0)
+ assertEquals(sizeIfKnown, count);
+
+ // Assert that forEach now produces no elements
+ spliterator.forEachRemaining(boxingAdapter.apply(
+ e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
+
+ Spliterator<T> split = spliterator.trySplit();
+ assertNull(split);
+ }
+ else {
+ List<T> leafDest = new ArrayList<>();
+ Consumer<T> addToLeafDest = boxingAdapter.apply(leafDest::add);
+ spliterator.forEachRemaining(addToLeafDest);
+
+ if (sizeIfKnown >= 0)
+ assertEquals(sizeIfKnown, leafDest.size());
+
+ // Assert that forEach now produces no elements
+ spliterator.tryAdvance(boxingAdapter.apply(
+ e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
+
+ Spliterator<T> split = spliterator.trySplit();
+ assertNull(split);
+
+ dest.addAll(leafDest);
+ }
+ }
+ }
+
+ private static <T, S extends Spliterator<T>> void testSplitUntilNull(
+ Collection<T> exp,
+ Supplier<S> supplier,
+ UnaryOperator<Consumer<T>> boxingAdapter,
+ ContentAsserter<T> asserter) {
+ Spliterator<T> s = supplier.get();
+ boolean isOrdered = s.hasCharacteristics(Spliterator.ORDERED);
+ assertSpliterator(s);
+
+ List<T> splits = new ArrayList<>();
+ Consumer<T> c = boxingAdapter.apply(splits::add);
+
+ testSplitUntilNull(new SplitNode<T>(c, s));
+ asserter.assertContents(splits, exp, isOrdered);
+ }
+
+ private static class SplitNode<T> {
+ // Constant for every node
+ final Consumer<T> c;
+ final int rootCharacteristics;
+
+ final Spliterator<T> s;
+
+ SplitNode(Consumer<T> c, Spliterator<T> s) {
+ this(c, s.characteristics(), s);
+ }
+
+ private SplitNode(Consumer<T> c, int rootCharacteristics, Spliterator<T> s) {
+ this.c = c;
+ this.rootCharacteristics = rootCharacteristics;
+ this.s = s;
+ }
+
+ SplitNode<T> fromSplit(Spliterator<T> split) {
+ return new SplitNode<>(c, rootCharacteristics, split);
+ }
+ }
+
+ /**
+ * Set the maximum stack capacity to 0.25MB. This should be more than enough to detect a bad spliterator
+ * while not unduly disrupting test infrastructure given the test data sizes that are used are small.
+ * Note that j.u.c.ForkJoinPool sets the max queue size to 64M (1 << 26).
+ */
+ private static final int MAXIMUM_STACK_CAPACITY = 1 << 18; // 0.25MB
+
+ private static <T> void testSplitUntilNull(SplitNode<T> e) {
+ // Use an explicit stack to avoid a StackOverflowException when testing a Spliterator
+ // that when repeatedly split produces a right-balanced (and maybe degenerate) tree, or
+ // for a spliterator that is badly behaved.
+ Deque<SplitNode<T>> stack = new ArrayDeque<>();
+ stack.push(e);
+
+ int iteration = 0;
+ while (!stack.isEmpty()) {
+ assertTrue(iteration++ < MAXIMUM_STACK_CAPACITY, "Exceeded maximum stack modification count of 1 << 18");
+
+ e = stack.pop();
+ Spliterator<T> parentAndRightSplit = e.s;
+
+ long parentEstimateSize = parentAndRightSplit.estimateSize();
+ assertTrue(parentEstimateSize >= 0,
+ String.format("Split size estimate %d < 0", parentEstimateSize));
+
+ long parentSize = parentAndRightSplit.getExactSizeIfKnown();
+ Spliterator<T> leftSplit = parentAndRightSplit.trySplit();
+ if (leftSplit == null) {
+ parentAndRightSplit.forEachRemaining(e.c);
+ continue;
+ }
+
+ assertSpliterator(leftSplit, e.rootCharacteristics);
+ assertSpliterator(parentAndRightSplit, e.rootCharacteristics);
+
+ if (parentEstimateSize != Long.MAX_VALUE && leftSplit.estimateSize() > 0
+ && parentAndRightSplit.estimateSize() > 0) {
+ assertTrue(leftSplit.estimateSize() < parentEstimateSize,
+ String.format("Left split size estimate %d >= parent split size estimate %d",
+ leftSplit.estimateSize(), parentEstimateSize));
+ assertTrue(parentAndRightSplit.estimateSize() < parentEstimateSize,
+ String.format("Right split size estimate %d >= parent split size estimate %d",
+ leftSplit.estimateSize(), parentEstimateSize));
+ }
+ else {
+ assertTrue(leftSplit.estimateSize() <= parentEstimateSize,
+ String.format("Left split size estimate %d > parent split size estimate %d",
+ leftSplit.estimateSize(), parentEstimateSize));
+ assertTrue(parentAndRightSplit.estimateSize() <= parentEstimateSize,
+ String.format("Right split size estimate %d > parent split size estimate %d",
+ leftSplit.estimateSize(), parentEstimateSize));
+ }
+
+ long leftSize = leftSplit.getExactSizeIfKnown();
+ long rightSize = parentAndRightSplit.getExactSizeIfKnown();
+ if (parentSize >= 0 && leftSize >= 0 && rightSize >= 0)
+ assertEquals(parentSize, leftSize + rightSize,
+ String.format("exact left split size %d + exact right split size %d != parent exact split size %d",
+ leftSize, rightSize, parentSize));
+
+ // Add right side to stack first so left side is popped off first
+ stack.push(e.fromSplit(parentAndRightSplit));
+ stack.push(e.fromSplit(leftSplit));
+ }
+ }
+
+ private static void assertSpliterator(Spliterator<?> s, int rootCharacteristics) {
+ if ((rootCharacteristics & Spliterator.SUBSIZED) != 0) {
+ assertTrue(s.hasCharacteristics(Spliterator.SUBSIZED),
+ "Child split is not SUBSIZED when root split is SUBSIZED");
+ }
+ assertSpliterator(s);
+ }
+
+ private static void assertSpliterator(Spliterator<?> s) {
+ if (s.hasCharacteristics(Spliterator.SUBSIZED)) {
+ assertTrue(s.hasCharacteristics(Spliterator.SIZED));
+ }
+ if (s.hasCharacteristics(Spliterator.SIZED)) {
+ assertTrue(s.estimateSize() != Long.MAX_VALUE);
+ assertTrue(s.getExactSizeIfKnown() >= 0);
+ }
+ try {
+ s.getComparator();
+ assertTrue(s.hasCharacteristics(Spliterator.SORTED));
+ } catch (IllegalStateException e) {
+ assertFalse(s.hasCharacteristics(Spliterator.SORTED));
+ }
+ }
+
+ private static<T> void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered) {
+ if (isOrdered) {
+ assertEquals(actual, expected);
+ }
+ else {
+ LambdaTestHelpers.assertContentsUnordered(actual, expected);
+ }
+ }
+
+ private static void executeAndCatch(Class<? extends Exception> expected, Runnable r) {
+ Exception caught = null;
+ try {
+ r.run();
+ }
+ catch (Exception e) {
+ caught = e;
+ }
+
+ assertNotNull(caught,
+ String.format("No Exception was thrown, expected an Exception of %s to be thrown",
+ expected.getName()));
+ assertTrue(expected.isInstance(caught),
+ String.format("Exception thrown %s not an instance of %s",
+ caught.getClass().getName(), expected.getName()));
+ }
+
+ static<U> void mixedTraverseAndSplit(Consumer<U> b, Spliterator<U> splTop) {
+ Spliterator<U> spl1, spl2, spl3;
+ splTop.tryAdvance(b);
+ spl2 = splTop.trySplit();
+ if (spl2 != null) {
+ spl2.tryAdvance(b);
+ spl1 = spl2.trySplit();
+ if (spl1 != null) {
+ spl1.tryAdvance(b);
+ spl1.forEachRemaining(b);
+ }
+ spl2.tryAdvance(b);
+ spl2.forEachRemaining(b);
+ }
+ splTop.tryAdvance(b);
+ spl3 = splTop.trySplit();
+ if (spl3 != null) {
+ spl3.tryAdvance(b);
+ spl3.forEachRemaining(b);
+ }
+ splTop.tryAdvance(b);
+ splTop.forEachRemaining(b);
+ }
+
+ static void mixedTraverseAndSplit(IntConsumer b, Spliterator.OfInt splTop) {
+ Spliterator.OfInt spl1, spl2, spl3;
+ splTop.tryAdvance(b);
+ spl2 = splTop.trySplit();
+ if (spl2 != null) {
+ spl2.tryAdvance(b);
+ spl1 = spl2.trySplit();
+ if (spl1 != null) {
+ spl1.tryAdvance(b);
+ spl1.forEachRemaining(b);
+ }
+ spl2.tryAdvance(b);
+ spl2.forEachRemaining(b);
+ }
+ splTop.tryAdvance(b);
+ spl3 = splTop.trySplit();
+ if (spl3 != null) {
+ spl3.tryAdvance(b);
+ spl3.forEachRemaining(b);
+ }
+ splTop.tryAdvance(b);
+ splTop.forEachRemaining(b);
+ }
+ static void mixedTraverseAndSplit(LongConsumer b, Spliterator.OfLong splTop) {
+ Spliterator.OfLong spl1, spl2, spl3;
+ splTop.tryAdvance(b);
+ spl2 = splTop.trySplit();
+ if (spl2 != null) {
+ spl2.tryAdvance(b);
+ spl1 = spl2.trySplit();
+ if (spl1 != null) {
+ spl1.tryAdvance(b);
+ spl1.forEachRemaining(b);
+ }
+ spl2.tryAdvance(b);
+ spl2.forEachRemaining(b);
+ }
+ splTop.tryAdvance(b);
+ spl3 = splTop.trySplit();
+ if (spl3 != null) {
+ spl3.tryAdvance(b);
+ spl3.forEachRemaining(b);
+ }
+ splTop.tryAdvance(b);
+ splTop.forEachRemaining(b);
+ }
+
+ static void mixedTraverseAndSplit(DoubleConsumer b, Spliterator.OfDouble splTop) {
+ Spliterator.OfDouble spl1, spl2, spl3;
+ splTop.tryAdvance(b);
+ spl2 = splTop.trySplit();
+ if (spl2 != null) {
+ spl2.tryAdvance(b);
+ spl1 = spl2.trySplit();
+ if (spl1 != null) {
+ spl1.tryAdvance(b);
+ spl1.forEachRemaining(b);
+ }
+ spl2.tryAdvance(b);
+ spl2.forEachRemaining(b);
+ }
+ splTop.tryAdvance(b);
+ spl3 = splTop.trySplit();
+ if (spl3 != null) {
+ spl3.tryAdvance(b);
+ spl3.forEachRemaining(b);
+ }
+ splTop.tryAdvance(b);
+ splTop.forEachRemaining(b);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/StatefulTestOp.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.function.IntFunction;
+
+/**
+ * The base type for a stateful test operation.
+ */
+interface StatefulTestOp<E> extends IntermediateTestOp<E, E> {
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public static<T> AbstractPipeline chain(AbstractPipeline upstream,
+ StatefulTestOp op) {
+ switch (op.outputShape()) {
+ case REFERENCE:
+ return new ReferencePipeline.StatefulOp<Object, T>(upstream, op.inputShape(), op.opGetFlags()) {
+ @Override
+ Sink opWrapSink(int flags, Sink sink) {
+ return op.opWrapSink(flags, isParallel(), sink);
+ }
+
+ @Override
+ <P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper,
+ Spliterator<P_IN> spliterator) {
+ return op.opEvaluateParallelLazy(helper, spliterator);
+ }
+
+ @Override
+ <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+ Spliterator<P_IN> spliterator,
+ IntFunction<T[]> generator) {
+ return op.opEvaluateParallel(helper, spliterator, generator);
+ }
+ };
+ case INT_VALUE:
+ return new IntPipeline.StatefulOp<Object>(upstream, op.inputShape(), op.opGetFlags()) {
+ @Override
+ Sink opWrapSink(int flags, Sink sink) {
+ return op.opWrapSink(flags, isParallel(), sink);
+ }
+
+ @Override
+ <P_IN> Spliterator<Integer> opEvaluateParallelLazy(PipelineHelper<Integer> helper,
+ Spliterator<P_IN> spliterator) {
+ return op.opEvaluateParallelLazy(helper, spliterator);
+ }
+
+ @Override
+ <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
+ Spliterator<P_IN> spliterator,
+ IntFunction<Integer[]> generator) {
+ return (Node<Integer>) op.opEvaluateParallel(helper, spliterator, generator);
+ }
+ };
+ case LONG_VALUE:
+ return new LongPipeline.StatefulOp<Object>(upstream, op.inputShape(), op.opGetFlags()) {
+ @Override
+ Sink opWrapSink(int flags, Sink sink) {
+ return op.opWrapSink(flags, isParallel(), sink);
+ }
+
+ @Override
+ <P_IN> Spliterator<Long> opEvaluateParallelLazy(PipelineHelper<Long> helper,
+ Spliterator<P_IN> spliterator) {
+ return op.opEvaluateParallelLazy(helper, spliterator);
+ }
+
+ @Override
+ <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
+ Spliterator<P_IN> spliterator,
+ IntFunction<Long[]> generator) {
+ return (Node<Long>) op.opEvaluateParallel(helper, spliterator, generator);
+ }
+ };
+ case DOUBLE_VALUE:
+ return new DoublePipeline.StatefulOp<Object>(upstream, op.inputShape(), op.opGetFlags()) {
+ @Override
+ Sink opWrapSink(int flags, Sink sink) {
+ return op.opWrapSink(flags, isParallel(), sink);
+ }
+
+ @Override
+ <P_IN> Spliterator<Double> opEvaluateParallelLazy(PipelineHelper<Double> helper,
+ Spliterator<P_IN> spliterator) {
+ return op.opEvaluateParallelLazy(helper, spliterator);
+ }
+
+ @Override
+ <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
+ Spliterator<P_IN> spliterator,
+ IntFunction<Double[]> generator) {
+ return (Node<Double>) op.opEvaluateParallel(helper, spliterator, generator);
+ }
+ };
+ default: throw new IllegalStateException(op.outputShape().toString());
+ }
+ }
+
+ default StreamShape inputShape() { return StreamShape.REFERENCE; }
+
+ default StreamShape outputShape() { return StreamShape.REFERENCE; }
+
+ default int opGetFlags() { return 0; }
+
+ Sink<E> opWrapSink(int flags, boolean parallel, Sink<E> sink);
+
+ @SuppressWarnings("unchecked")
+ default <P_IN> Spliterator<E> opEvaluateParallelLazy(PipelineHelper<E> helper,
+ Spliterator<P_IN> spliterator) {
+ return opEvaluateParallel(helper, spliterator, i -> (E[]) new Object[i]).spliterator();
+ }
+
+ <P_IN> Node<E> opEvaluateParallel(PipelineHelper<E> helper,
+ Spliterator<P_IN> spliterator,
+ IntFunction<E[]> generator);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/StatelessTestOp.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * The base type of a stateless test operation
+ */
+interface StatelessTestOp<E_IN, E_OUT> extends IntermediateTestOp<E_IN, E_OUT> {
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public static<T> AbstractPipeline chain(AbstractPipeline upstream,
+ StatelessTestOp<?, T> op) {
+ int flags = op.opGetFlags();
+ switch (op.outputShape()) {
+ case REFERENCE:
+ return new ReferencePipeline.StatelessOp<Object, T>(upstream, op.inputShape(), flags) {
+ public Sink opWrapSink(int flags, Sink<T> sink) {
+ return op.opWrapSink(flags, isParallel(), sink);
+ }
+ };
+ case INT_VALUE:
+ return new IntPipeline.StatelessOp<Object>(upstream, op.inputShape(), flags) {
+ public Sink opWrapSink(int flags, Sink sink) {
+ return op.opWrapSink(flags, isParallel(), sink);
+ }
+ };
+ case LONG_VALUE:
+ return new LongPipeline.StatelessOp<Object>(upstream, op.inputShape(), flags) {
+ @Override
+ Sink opWrapSink(int flags, Sink sink) {
+ return op.opWrapSink(flags, isParallel(), sink);
+ }
+ };
+ case DOUBLE_VALUE:
+ return new DoublePipeline.StatelessOp<Object>(upstream, op.inputShape(), flags) {
+ @Override
+ Sink opWrapSink(int flags, Sink sink) {
+ return op.opWrapSink(flags, isParallel(), sink);
+ }
+ };
+ default: throw new IllegalStateException(op.outputShape().toString());
+ }
+ }
+
+ default StreamShape inputShape() { return StreamShape.REFERENCE; }
+
+ default StreamShape outputShape() { return StreamShape.REFERENCE; }
+
+ default int opGetFlags() { return 0; }
+
+ Sink<E_IN> opWrapSink(int flags, boolean parallel, Sink<E_OUT> sink);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/StreamOpFlagTestHelper.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.EnumSet;
+
+public class StreamOpFlagTestHelper {
+
+ /** EnumSet containing stream flags */
+ private static final EnumSet<StreamOpFlag> allStreamFlags;
+
+ static {
+ allStreamFlags = EnumSet.allOf(StreamOpFlag.class);
+ for (StreamOpFlag f : EnumSet.allOf(StreamOpFlag.class))
+ if (!f.isStreamFlag())
+ allStreamFlags.remove(f);
+ }
+
+
+ static EnumSet<StreamOpFlag> allStreamFlags() {
+ // EnumSet is mutable
+ return allStreamFlags.clone();
+ }
+
+ public static boolean isStreamOrdered(Stream<?> s) {
+ return StreamOpFlag.ORDERED.isKnown(OpTestCase.getStreamFlags(s));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/StreamTestDataProvider.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+
+import java.util.*;
+import java.util.Spliterators;
+import java.util.function.Supplier;
+
+/**
+ * StreamTestDataProvider
+ *
+ * @author Brian Goetz
+ */
+/** TestNG DataProvider for ref-valued streams */
+public class StreamTestDataProvider {
+ private static final Integer[] to0 = new Integer[0];
+ private static final Integer[] to1 = new Integer[1];
+ private static final Integer[] to10 = new Integer[10];
+ private static final Integer[] to100 = new Integer[100];
+ private static final Integer[] to1000 = new Integer[1000];
+ private static final Integer[] reversed = new Integer[100];
+ private static final Integer[] ones = new Integer[100];
+ private static final Integer[] twice = new Integer[200];
+ private static final Integer[] pseudoRandom;
+
+ private static final Object[][] testData;
+ private static final Object[][] withNullTestData;
+ private static final Object[][] spliteratorTestData;
+
+ static {
+ Integer[][] arrays = {to0, to1, to10, to100, to1000};
+ for (Integer[] arr : arrays) {
+ for (int i = 0; i < arr.length; i++) {
+ arr[i] = i;
+ }
+ }
+ for (int i = 0; i < reversed.length; i++) {
+ reversed[i] = reversed.length - i;
+ }
+ for (int i = 0; i < ones.length; i++) {
+ ones[i] = 1;
+ }
+ System.arraycopy(to100, 0, twice, 0, to100.length);
+ System.arraycopy(to100, 0, twice, to100.length, to100.length);
+ pseudoRandom = new Integer[LambdaTestHelpers.LONG_STRING.length()];
+ for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
+ pseudoRandom[i] = (int) LambdaTestHelpers.LONG_STRING.charAt(i);
+ }
+ }
+
+ static final Object[][] arrays = {
+ {"empty", to0},
+ {"0..1", to1},
+ {"0..10", to10},
+ {"0..100", to100},
+ {"0..1000", to1000},
+ {"100x[1]", ones},
+ {"2x[0..100]", twice},
+ {"reverse 0..100", reversed},
+ {"pseudorandom", pseudoRandom}
+ };
+
+ static {
+ {
+ List<Object[]> list = new ArrayList<>();
+ for (Object[] data : arrays) {
+ final Object name = data[0];
+ final Integer[] ints = (Integer[])data[1];
+ final List<Integer> intsAsList = Arrays.asList(ints);
+
+ list.add(arrayDataDescr("array:" + name, ints));
+ list.add(collectionDataDescr("ArrayList.asList:" + name, intsAsList));
+ list.add(collectionDataDescr("ArrayList:" + name, new ArrayList<>(intsAsList)));
+ list.add(streamDataDescr("DelegatingStream(ArrayList):" + name,
+ () -> new ArrayList<>(intsAsList).stream()));
+ List<Integer> aList = new ArrayList<>(intsAsList);
+ if (LambdaTestMode.isNormalMode()) {
+ // Only include sub-lists for normal test execution mode
+ // This data is serialization-hostile since the state of the
+ // deserialized sub-list will be out of sync with the
+ // enclosing list.
+ list.add(collectionDataDescr("ArrayList.Sublist:" + name,
+ (ints.length) <= 1 ? aList.subList(0, 0) : aList.subList(1, ints.length / 2)));
+ }
+ list.add(collectionDataDescr("LinkedList:" + name, new LinkedList<>(intsAsList)));
+ list.add(collectionDataDescr("HashSet:" + name, new HashSet<>(intsAsList)));
+ list.add(collectionDataDescr("LinkedHashSet:" + name, new LinkedHashSet<>(intsAsList)));
+ list.add(collectionDataDescr("TreeSet:" + name, new TreeSet<>(intsAsList)));
+ SpinedBuffer<Integer> spinedBuffer = new SpinedBuffer<>();
+ intsAsList.forEach(spinedBuffer);
+ list.add(sbDataDescr("SpinedBuffer:" + name, spinedBuffer));
+
+ // @@@ Add more
+ }
+ testData = list.toArray(new Object[0][]);
+ }
+
+ // Simple combination of numbers and null values, probably excessive but may catch
+ // errors for initialization/termination/sequence
+ // @@@ This is separate from the other data for now until nulls are consistently supported by
+ // all operations
+ {
+ List<Object[]> list = new ArrayList<>();
+ int size = 5;
+ for (int i = 0; i < (1 << size) - 2; i++) {
+ Integer[] content = new Integer[size];
+ for (int e = 0; e < size; e++) {
+ content[e] = (i & (1 << e)) > 0 ? e + 1 : null;
+ }
+
+ // ORDERED
+ list.add(arrayDataDescr("array:" + i, content));
+ // not ORDERED, DISTINCT
+ list.add(collectionDataDescr("HashSet:" + i, new HashSet<>(Arrays.asList(content))));
+ }
+
+ withNullTestData = list.toArray(new Object[0][]);
+ }
+
+ {
+ List<Object[]> spliterators = new ArrayList<>();
+ for (Object[] data : arrays) {
+ final Object name = data[0];
+ final Integer[] ints = (Integer[])data[1];
+
+ spliterators.add(splitDescr("Arrays.s(array):" + name,
+ () -> Arrays.spliterator(ints)));
+ spliterators.add(splitDescr("arrays.s(array,o,l):" + name,
+ () -> Arrays.spliterator(ints, 0, ints.length/2)));
+ spliterators.add(splitDescr("SpinedBuffer.s():" + name,
+ () -> {
+ SpinedBuffer<Integer> sb = new SpinedBuffer<>();
+ for (Integer i : ints)
+ sb.accept(i);
+ return sb.spliterator();
+ }));
+ spliterators.add(splitDescr("Iterators.s(Arrays.s(array).iterator(), size):" + name,
+ () -> Spliterators.spliterator(Arrays.asList(ints).iterator(), ints.length, 0)));
+ spliterators.add(splitDescr("Iterators.s(Arrays.s(array).iterator()):" + name,
+ () -> Spliterators.spliteratorUnknownSize(Arrays.asList(ints).iterator(), 0)));
+ // @@@ Add map and collection spliterators when spliterator() is exposed on Collection or Iterable
+ }
+ spliteratorTestData = spliterators.toArray(new Object[0][]);
+ }
+ }
+
+ static <T> Object[] arrayDataDescr(String description, T[] data) {
+ return new Object[] { description, TestData.Factory.ofArray(description, data)};
+ }
+
+ static <T> Object[] streamDataDescr(String description, Supplier<Stream<T>> supplier) {
+ return new Object[] { description, TestData.Factory.ofSupplier(description, supplier)};
+ }
+
+ static <T> Object[] collectionDataDescr(String description, Collection<T> data) {
+ return new Object[] { description, TestData.Factory.ofCollection(description, data)};
+ }
+
+ static <T> Object[] sbDataDescr(String description, SpinedBuffer<T> data) {
+ return new Object[] { description, TestData.Factory.ofSpinedBuffer(description, data)};
+ }
+
+ static <T> Object[] splitDescr(String description, Supplier<Spliterator<T>> ss) {
+ return new Object[] { description, ss };
+ }
+
+ // Return an array of ( String name, StreamTestData<Integer> )
+ @DataProvider(name = "StreamTestData<Integer>")
+ public static Object[][] makeStreamTestData() {
+ return testData;
+ }
+
+ @DataProvider(name = "withNull:StreamTestData<Integer>")
+ public static Object[][] makeStreamWithNullTestData() {
+ return withNullTestData;
+ }
+
+ // returns an array of (String name, Supplier<Spliterator<Integer>>)
+ @DataProvider(name = "Spliterator<Integer>")
+ public static Object[][] spliteratorProvider() {
+ return spliteratorTestData;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/StreamTestScenario.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * Test scenarios for reference streams.
+ *
+ * Each scenario is provided with a data source, a function that maps a fresh
+ * stream (as provided by the data source) to a new stream, and a sink to
+ * receive results. Each scenario describes a different way of computing the
+ * stream contents. The test driver will ensure that all scenarios produce
+ * the same output (modulo allowable differences in ordering).
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public enum StreamTestScenario implements OpTestCase.BaseStreamTestScenario {
+
+ STREAM_FOR_EACH(false) {
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ Stream<U> s = m.apply(source);
+ if (s.isParallel()) {
+ s = s.sequential();
+ }
+ s.forEach(b);
+ }
+ },
+
+ // Collec to list
+ STREAM_COLLECT(false) {
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ for (U t : m.apply(source).collect(Collectors.toList())) {
+ b.accept(t);
+ }
+ }
+ },
+
+ // To array
+ STREAM_TO_ARRAY(false) {
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ for (Object t : m.apply(source).toArray()) {
+ b.accept((U) t);
+ }
+ }
+ },
+
+ // Wrap as stream, and iterate in pull mode
+ STREAM_ITERATOR(false) {
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ for (Iterator<U> seqIter = m.apply(source).iterator(); seqIter.hasNext(); )
+ b.accept(seqIter.next());
+ }
+ },
+
+ // Wrap as stream, and spliterate then iterate in pull mode
+ STREAM_SPLITERATOR(false) {
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ for (Spliterator<U> spl = m.apply(source).spliterator(); spl.tryAdvance(b); ) {
+ }
+ }
+ },
+
+ // Wrap as stream, spliterate, then split a few times mixing advances with forEach
+ STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(source).spliterator());
+ }
+ },
+
+ // Wrap as stream, and spliterate then iterate in pull mode
+ STREAM_SPLITERATOR_FOREACH(false) {
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ m.apply(source).spliterator().forEachRemaining(b);
+ }
+ },
+
+ // Wrap as parallel stream + sequential
+ PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ m.apply(source).sequential().forEach(b);
+ }
+ },
+
+ // Wrap as parallel stream + forEachOrdered
+ PAR_STREAM_FOR_EACH_ORDERED(true) {
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ // @@@ Want to explicitly select ordered equalator
+ m.apply(source).forEachOrdered(b);
+ }
+ },
+
+ // Wrap as stream, and spliterate then iterate sequentially
+ PAR_STREAM_SPLITERATOR(true) {
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ for (Spliterator<U> spl = m.apply(source).spliterator(); spl.tryAdvance(b); ) {
+ }
+ }
+ },
+
+ // Wrap as stream, and spliterate then iterate sequentially
+ PAR_STREAM_SPLITERATOR_FOREACH(true) {
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ m.apply(source).spliterator().forEachRemaining(b);
+ }
+ },
+
+ // Wrap as parallel stream + toArray
+ PAR_STREAM_TO_ARRAY(true) {
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ for (Object t : m.apply(source).toArray())
+ b.accept((U) t);
+ }
+ },
+
+ // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
+ PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ Stream<U> s = m.apply(source);
+ Spliterator<U> sp = s.spliterator();
+ Stream<U> ss = StreamSupport.stream(() -> sp,
+ StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
+ | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED), true);
+ for (Object t : ss.toArray())
+ b.accept((U) t);
+ }
+ },
+
+ // Wrap as parallel stream + toArray and clear SIZED flag
+ PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ S_IN pipe1 = (S_IN) OpTestCase.chain(source,
+ new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+ Stream<U> pipe2 = m.apply(pipe1);
+
+ for (Object t : pipe2.toArray())
+ b.accept((U) t);
+ }
+ },
+
+ // Wrap as parallel + collect to list
+ PAR_STREAM_COLLECT_TO_LIST(true) {
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ for (U u : m.apply(source).collect(Collectors.toList()))
+ b.accept(u);
+ }
+ },
+
+ // Wrap sequential as parallel, + collect to list
+ STREAM_TO_PAR_STREAM_COLLECT_TO_LIST(true) {
+ public <T, S_IN extends BaseStream<T, S_IN>>
+ S_IN getStream(TestData<T, S_IN> data) {
+ return data.stream().parallel();
+ }
+
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ for (U u : m.apply(source).collect(Collectors.toList()))
+ b.accept(u);
+ }
+ },
+
+ // Wrap parallel as sequential,, + collect
+ PAR_STREAM_TO_STREAM_COLLECT_TO_LIST(true) {
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ for (U u : m.apply(source).collect(Collectors.toList()))
+ b.accept(u);
+ }
+ },
+
+ // Wrap as parallel stream + forEach synchronizing
+ PAR_STREAM_FOR_EACH(true, false) {
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ m.apply(source).forEach(e -> {
+ synchronized (data) {
+ b.accept(e);
+ }
+ });
+ }
+ },
+
+ // Wrap as parallel stream + forEach synchronizing and clear SIZED flag
+ PAR_STREAM_FOR_EACH_CLEAR_SIZED(true, false) {
+ <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+ S_IN pipe1 = (S_IN) OpTestCase.chain(source,
+ new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+ m.apply(pipe1).forEach(e -> {
+ synchronized (data) {
+ b.accept(e);
+ }
+ });
+ }
+ },
+ ;
+
+ // The set of scenarios that clean the SIZED flag
+ public static final Set<StreamTestScenario> CLEAR_SIZED_SCENARIOS = Collections.unmodifiableSet(
+ EnumSet.of(PAR_STREAM_TO_ARRAY_CLEAR_SIZED, PAR_STREAM_FOR_EACH_CLEAR_SIZED));
+
+ private final boolean isParallel;
+
+ private final boolean isOrdered;
+
+ StreamTestScenario(boolean isParallel) {
+ this(isParallel, true);
+ }
+
+ StreamTestScenario(boolean isParallel, boolean isOrdered) {
+ this.isParallel = isParallel;
+ this.isOrdered = isOrdered;
+ }
+
+ public StreamShape getShape() {
+ return StreamShape.REFERENCE;
+ }
+
+ public boolean isParallel() {
+ return isParallel;
+ }
+
+ public boolean isOrdered() {
+ return isOrdered;
+ }
+
+ public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+ void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
+ try (S_IN source = getStream(data)) {
+ run(data, source, b, (Function<S_IN, Stream<U>>) m);
+ }
+ }
+
+ abstract <T, U, S_IN extends BaseStream<T, S_IN>>
+ void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/TestData.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.DoubleConsumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+import java.util.function.Supplier;
+import java.util.function.ToIntFunction;
+
+/** Describes a test data set for use in stream tests */
+public interface TestData<T, S extends BaseStream<T, S>>
+ extends Iterable<T> {
+
+ default int size() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ default Iterator<T> iterator() {
+ return Spliterators.iterator(spliterator());
+ }
+
+ Spliterator<T> spliterator();
+
+ default boolean isOrdered() {
+ return spliterator().hasCharacteristics(Spliterator.ORDERED);
+ }
+
+ StreamShape getShape();
+
+ default <A extends Collection<? super T>> A into(A target) {
+ spliterator().forEachRemaining(target::add);
+ return target;
+ }
+
+ S stream();
+
+ S parallelStream();
+
+ public interface OfRef<T> extends TestData<T, Stream<T>> { }
+
+ public interface OfInt extends TestData<Integer, IntStream> { }
+
+ public interface OfLong extends TestData<Long, LongStream> { }
+
+ public interface OfDouble extends TestData<Double, DoubleStream> { }
+
+ // @@@ Temporary garbage class to avoid triggering bugs with lambdas in static methods in interfaces
+ public static class Factory {
+ public static <T> OfRef<T> ofArray(String name, T[] array) {
+ return new AbstractTestData.RefTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
+ Arrays::spliterator, a -> a.length);
+ }
+
+ public static <T> OfRef<T> ofCollection(String name, Collection<T> collection) {
+ return new AbstractTestData.RefTestData<>(name, collection, Collection::stream, Collection::parallelStream,
+ Collection::spliterator, Collection::size);
+ }
+
+ public static <T> OfRef<T> ofSpinedBuffer(String name, SpinedBuffer<T> buffer) {
+ return new AbstractTestData.RefTestData<>(name, buffer,
+ b -> StreamSupport.stream(b.spliterator(), false),
+ b -> StreamSupport.stream(b.spliterator(), true),
+ SpinedBuffer::spliterator,
+ b -> (int) b.count());
+ }
+
+ public static <T> OfRef<T> ofSupplier(String name, Supplier<Stream<T>> supplier) {
+ return new AbstractTestData.RefTestData<>(name, supplier,
+ Supplier::get,
+ s -> s.get().parallel(),
+ s -> s.get().spliterator(),
+ s -> (int) s.get().spliterator().getExactSizeIfKnown());
+ }
+
+ public static <T> OfRef<T> ofRefNode(String name, Node<T> node) {
+ return new AbstractTestData.RefTestData<>(name, node,
+ n -> StreamSupport.stream(n::spliterator, Spliterator.SIZED | Spliterator.ORDERED, false),
+ n -> StreamSupport.stream(n::spliterator, Spliterator.SIZED | Spliterator.ORDERED, true),
+ Node::spliterator,
+ n -> (int) n.count());
+ }
+
+ // int factories
+ public static <T> OfInt ofArray(String name, int[] array) {
+ return new AbstractTestData.IntTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
+ Arrays::spliterator, a -> a.length);
+ }
+
+ public static OfInt ofSpinedBuffer(String name, SpinedBuffer.OfInt buffer) {
+ return new AbstractTestData.IntTestData<>(name, buffer,
+ b -> StreamSupport.intStream(b.spliterator(), false),
+ b -> StreamSupport.intStream(b.spliterator(), true),
+ SpinedBuffer.OfInt::spliterator,
+ b -> (int) b.count());
+ }
+
+ public static OfInt ofIntSupplier(String name, Supplier<IntStream> supplier) {
+ return new AbstractTestData.IntTestData<>(name, supplier,
+ Supplier::get,
+ s -> s.get().parallel(),
+ s -> s.get().spliterator(),
+ s -> (int) s.get().spliterator().getExactSizeIfKnown());
+ }
+
+ public static OfInt ofNode(String name, Node.OfInt node) {
+ int characteristics = Spliterator.SIZED | Spliterator.ORDERED;
+ return new AbstractTestData.IntTestData<>(name, node,
+ n -> StreamSupport.intStream(n::spliterator, characteristics, false),
+ n -> StreamSupport.intStream(n::spliterator, characteristics, true),
+ Node.OfInt::spliterator,
+ n -> (int) n.count());
+ }
+
+ // long factories
+ public static <T> OfLong ofArray(String name, long[] array) {
+ return new AbstractTestData.LongTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
+ Arrays::spliterator, a -> a.length);
+ }
+
+ public static OfLong ofSpinedBuffer(String name, SpinedBuffer.OfLong buffer) {
+ return new AbstractTestData.LongTestData<>(name, buffer,
+ b -> StreamSupport.longStream(b.spliterator(), false),
+ b -> StreamSupport.longStream(b.spliterator(), true),
+ SpinedBuffer.OfLong::spliterator,
+ b -> (int) b.count());
+ }
+
+ public static OfLong ofLongSupplier(String name, Supplier<LongStream> supplier) {
+ return new AbstractTestData.LongTestData<>(name, supplier,
+ Supplier::get,
+ s -> s.get().parallel(),
+ s -> s.get().spliterator(),
+ s -> (int) s.get().spliterator().getExactSizeIfKnown());
+ }
+
+ public static OfLong ofNode(String name, Node.OfLong node) {
+ int characteristics = Spliterator.SIZED | Spliterator.ORDERED;
+ return new AbstractTestData.LongTestData<>(name, node,
+ n -> StreamSupport.longStream(n::spliterator, characteristics, false),
+ n -> StreamSupport.longStream(n::spliterator, characteristics, true),
+ Node.OfLong::spliterator,
+ n -> (int) n.count());
+ }
+
+ // double factories
+ public static <T> OfDouble ofArray(String name, double[] array) {
+ return new AbstractTestData.DoubleTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
+ Arrays::spliterator, a -> a.length);
+ }
+
+ public static OfDouble ofSpinedBuffer(String name, SpinedBuffer.OfDouble buffer) {
+ return new AbstractTestData.DoubleTestData<>(name, buffer,
+ b -> StreamSupport.doubleStream(b.spliterator(), false),
+ b -> StreamSupport.doubleStream(b.spliterator(), true),
+ SpinedBuffer.OfDouble::spliterator,
+ b -> (int) b.count());
+ }
+
+ public static OfDouble ofDoubleSupplier(String name, Supplier<DoubleStream> supplier) {
+ return new AbstractTestData.DoubleTestData<>(name, supplier,
+ Supplier::get,
+ s -> s.get().parallel(),
+ s -> s.get().spliterator(),
+ s -> (int) s.get().spliterator().getExactSizeIfKnown());
+ }
+
+ public static OfDouble ofNode(String name, Node.OfDouble node) {
+ int characteristics = Spliterator.SIZED | Spliterator.ORDERED;
+ return new AbstractTestData.DoubleTestData<>(name, node,
+ n -> StreamSupport.doubleStream(n::spliterator, characteristics, false),
+ n -> StreamSupport.doubleStream(n::spliterator, characteristics, true),
+ Node.OfDouble::spliterator,
+ n -> (int) n.count());
+ }
+ }
+
+
+ abstract class AbstractTestData<T, S extends BaseStream<T, S>,
+ T_STATE,
+ T_SPLITR extends Spliterator<T>>
+ implements TestData<T, S> {
+ private final String name;
+ private final StreamShape shape;
+ protected final T_STATE state;
+ private final ToIntFunction<T_STATE> sizeFn;
+ private final Function<T_STATE, S> streamFn;
+ private final Function<T_STATE, S> parStreamFn;
+ private final Function<T_STATE, T_SPLITR> splitrFn;
+
+ AbstractTestData(String name,
+ StreamShape shape,
+ T_STATE state,
+ Function<T_STATE, S> streamFn,
+ Function<T_STATE, S> parStreamFn,
+ Function<T_STATE, T_SPLITR> splitrFn,
+ ToIntFunction<T_STATE> sizeFn) {
+ this.name = name;
+ this.shape = shape;
+ this.state = state;
+ this.streamFn = streamFn;
+ this.parStreamFn = parStreamFn;
+ this.splitrFn = splitrFn;
+ this.sizeFn = sizeFn;
+ }
+
+ @Override
+ public StreamShape getShape() {
+ return shape;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[" + name + "]";
+ }
+
+ @Override
+ public int size() {
+ return sizeFn.applyAsInt(state);
+ }
+
+ @Override
+ public T_SPLITR spliterator() {
+ return splitrFn.apply(state);
+ }
+
+ @Override
+ public S stream() {
+ return streamFn.apply(state);
+ }
+
+ @Override
+ public S parallelStream() {
+ return parStreamFn.apply(state);
+ }
+
+ public static class RefTestData<T, I>
+ extends AbstractTestData<T, Stream<T>, I, Spliterator<T>>
+ implements TestData.OfRef<T> {
+
+ protected RefTestData(String name,
+ I state,
+ Function<I, Stream<T>> streamFn,
+ Function<I, Stream<T>> parStreamFn,
+ Function<I, Spliterator<T>> splitrFn,
+ ToIntFunction<I> sizeFn) {
+ super(name, StreamShape.REFERENCE, state, streamFn, parStreamFn, splitrFn, sizeFn);
+ }
+
+ }
+
+ static class IntTestData<I>
+ extends AbstractTestData<Integer, IntStream, I, Spliterator.OfInt>
+ implements TestData.OfInt {
+
+ protected IntTestData(String name,
+ I state,
+ Function<I, IntStream> streamFn,
+ Function<I, IntStream> parStreamFn,
+ Function<I, Spliterator.OfInt> splitrFn,
+ ToIntFunction<I> sizeFn) {
+ super(name, StreamShape.INT_VALUE, state, streamFn, parStreamFn, splitrFn, sizeFn);
+ }
+
+ @Override
+ public PrimitiveIterator.OfInt iterator() {
+ return Spliterators.iterator(spliterator());
+ }
+
+ @Override
+ public <A extends Collection<? super Integer>> A into(A target) {
+ spliterator().forEachRemaining((IntConsumer) target::add);
+ return target;
+ }
+ }
+
+ static class LongTestData<I>
+ extends AbstractTestData<Long, LongStream, I, Spliterator.OfLong>
+ implements TestData.OfLong {
+
+ protected LongTestData(String name,
+ I state,
+ Function<I, LongStream> streamFn,
+ Function<I, LongStream> parStreamFn,
+ Function<I, Spliterator.OfLong> splitrFn,
+ ToIntFunction<I> sizeFn) {
+ super(name, StreamShape.LONG_VALUE, state, streamFn, parStreamFn, splitrFn, sizeFn);
+ }
+
+ @Override
+ public PrimitiveIterator.OfLong iterator() {
+ return Spliterators.iterator(spliterator());
+ }
+
+ @Override
+ public <A extends Collection<? super Long>> A into(A target) {
+ spliterator().forEachRemaining((LongConsumer) target::add);
+ return target;
+ }
+ }
+
+ static class DoubleTestData<I>
+ extends AbstractTestData<Double, DoubleStream, I, Spliterator.OfDouble>
+ implements OfDouble {
+
+ protected DoubleTestData(String name,
+ I state,
+ Function<I, DoubleStream> streamFn,
+ Function<I, DoubleStream> parStreamFn,
+ Function<I, Spliterator.OfDouble> splitrFn,
+ ToIntFunction<I> sizeFn) {
+ super(name, StreamShape.DOUBLE_VALUE, state, streamFn, parStreamFn, splitrFn, sizeFn);
+ }
+
+ @Override
+ public PrimitiveIterator.OfDouble iterator() {
+ return Spliterators.iterator(spliterator());
+ }
+
+ @Override
+ public <A extends Collection<? super Double>> A into(A target) {
+ spliterator().forEachRemaining((DoubleConsumer) target::add);
+ return target;
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/TestFlagExpectedOp.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.Assert;
+
+import java.util.EnumSet;
+
+class TestFlagExpectedOp<T> extends FlagDeclaringOp<T> {
+
+ static class Builder<T> {
+ final int flags;
+ StreamShape shape = StreamShape.REFERENCE;
+
+ EnumSet<StreamOpFlag> known = EnumSet.noneOf(StreamOpFlag.class);
+ EnumSet<StreamOpFlag> preserve = EnumSet.noneOf(StreamOpFlag.class);
+ EnumSet<StreamOpFlag> notKnown = EnumSet.noneOf(StreamOpFlag.class);
+
+ Builder(int flags) {
+ this.flags = flags;
+ }
+
+ Builder<T> known(EnumSet<StreamOpFlag> known) {
+ this.known = known;
+ return this;
+ }
+
+ Builder<T> preserve(EnumSet<StreamOpFlag> preserve) {
+ this.preserve = preserve;
+ return this;
+ }
+
+ Builder<T> notKnown(EnumSet<StreamOpFlag> notKnown) {
+ this.notKnown = notKnown;
+ return this;
+ }
+
+ Builder<T> shape(StreamShape shape) {
+ this.shape = shape;
+ return this;
+ }
+
+ TestFlagExpectedOp<T> build() {
+ return new TestFlagExpectedOp<>(flags, known, preserve, notKnown, shape);
+ }
+ }
+
+ final EnumSet<StreamOpFlag> known;
+ final EnumSet<StreamOpFlag> preserve;
+ final EnumSet<StreamOpFlag> notKnown;
+ final StreamShape shape;
+
+ TestFlagExpectedOp(int flags,
+ EnumSet<StreamOpFlag> known,
+ EnumSet<StreamOpFlag> preserve,
+ EnumSet<StreamOpFlag> notKnown) {
+ this(flags, known, preserve, notKnown, StreamShape.REFERENCE);
+ }
+
+ TestFlagExpectedOp(int flags,
+ EnumSet<StreamOpFlag> known,
+ EnumSet<StreamOpFlag> preserve,
+ EnumSet<StreamOpFlag> notKnown,
+ StreamShape shape) {
+ super(flags);
+ this.known = known;
+ this.preserve = preserve;
+ this.notKnown = notKnown;
+ this.shape = shape;
+ }
+
+ @Override
+ public StreamShape outputShape() {
+ return shape;
+ }
+
+ @Override
+ public StreamShape inputShape() {
+ return shape;
+ }
+
+ @Override
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public Sink<T> opWrapSink(int flags, boolean parallel, Sink upstream) {
+ assertFlags(flags);
+ return upstream;
+ }
+
+ private void assertFlags(int flags) {
+ for (StreamOpFlag f : known) {
+ Assert.assertTrue(f.isKnown(flags),
+ String.format("Flag %s is not known, but should be known.", f.toString()));
+ }
+
+ for (StreamOpFlag f : preserve) {
+ Assert.assertTrue(f.isPreserved(flags),
+ String.format("Flag %s is not preserved, but should be preserved.", f.toString()));
+ }
+
+ for (StreamOpFlag f : notKnown) {
+ Assert.assertFalse(f.isKnown(flags),
+ String.format("Flag %s is known, but should be not known.", f.toString()));
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/ThowableHelper.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+public final class ThowableHelper {
+
+ public static void checkException(Class<? extends Exception> ce, Runnable r) {
+ Exception caught = null;
+ try {
+ r.run();
+ } catch (Exception e) {
+ caught = e;
+ }
+
+ assertNotNull(caught);
+ assertTrue(ce.isInstance(caught));
+ }
+
+ public static void checkNPE(Runnable r) {
+ checkException(NullPointerException.class, r);
+ }
+
+ public static void checkISE(Runnable r) {
+ checkException(IllegalStateException.class, r);
+ }
+}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/CollectorOps.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import org.testng.Assert;
-
-import java.util.Spliterator;
-import java.util.function.IntFunction;
-
-/** Test helper class for java.util.stream test framework */
-public final class CollectorOps {
- private CollectorOps() { }
-
- public static <E_IN> StatefulTestOp<E_IN> collector() {
- return new StatefulCollector<>(0, StreamShape.REFERENCE);
- }
-
- /* Utility classes for collecting output of intermediate pipeline stages */
- public static class StatefulCollector<E_IN> implements StatefulTestOp<E_IN> {
- private final int opFlags;
- private final StreamShape inputShape;
-
- public StatefulCollector(int opFlags, StreamShape inputShape) {
- this.opFlags = opFlags;
- this.inputShape = inputShape;
- }
-
- @Override
- public StreamShape inputShape() {
- return inputShape;
- }
-
- @Override
- public StreamShape outputShape() {
- return inputShape;
- }
-
- @Override
- public int opGetFlags() {
- return opFlags;
- }
-
- @Override
- public Sink<E_IN> opWrapSink(int flags, boolean parallel, Sink<E_IN> sink) {
- return sink;
- }
-
- @Override
- public <P_IN> Node<E_IN> opEvaluateParallel(PipelineHelper<E_IN> helper,
- Spliterator<P_IN> spliterator,
- IntFunction<E_IN[]> generator) {
- return helper.evaluate(spliterator, false, generator);
- }
- }
-
- public static class TestParallelSizedOp<T> extends StatefulCollector<T> {
- public TestParallelSizedOp() {
- this(StreamShape.REFERENCE);
- }
-
- protected TestParallelSizedOp(StreamShape shape) {
- super(0, shape);
- }
-
- @Override
- public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
- Spliterator<P_IN> spliterator,
- IntFunction<T[]> generator) {
- int flags = helper.getStreamAndOpFlags();
-
- Assert.assertTrue(StreamOpFlag.SIZED.isKnown(flags));
- return super.opEvaluateParallel(helper, spliterator, generator);
- }
-
- public static class OfInt extends TestParallelSizedOp<Integer> {
- public OfInt() {
- super(StreamShape.INT_VALUE);
- }
- }
-
- public static class OfLong extends TestParallelSizedOp<Long> {
- public OfLong() {
- super(StreamShape.LONG_VALUE);
- }
- }
-
- public static class OfDouble extends TestParallelSizedOp<Double> {
- public OfDouble() {
- super(StreamShape.DOUBLE_VALUE);
- }
- }
- }
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/DefaultMethodStreams.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,984 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Comparator;
-import java.util.DoubleSummaryStatistics;
-import java.util.IntSummaryStatistics;
-import java.util.Iterator;
-import java.util.LongSummaryStatistics;
-import java.util.Optional;
-import java.util.OptionalDouble;
-import java.util.OptionalInt;
-import java.util.OptionalLong;
-import java.util.PrimitiveIterator;
-import java.util.Set;
-import java.util.Spliterator;
-import java.util.function.BiConsumer;
-import java.util.function.BiFunction;
-import java.util.function.BinaryOperator;
-import java.util.function.Consumer;
-import java.util.function.DoubleBinaryOperator;
-import java.util.function.DoubleConsumer;
-import java.util.function.DoubleFunction;
-import java.util.function.DoublePredicate;
-import java.util.function.DoubleToIntFunction;
-import java.util.function.DoubleToLongFunction;
-import java.util.function.DoubleUnaryOperator;
-import java.util.function.Function;
-import java.util.function.IntBinaryOperator;
-import java.util.function.IntConsumer;
-import java.util.function.IntFunction;
-import java.util.function.IntPredicate;
-import java.util.function.IntToDoubleFunction;
-import java.util.function.IntToLongFunction;
-import java.util.function.IntUnaryOperator;
-import java.util.function.LongBinaryOperator;
-import java.util.function.LongConsumer;
-import java.util.function.LongFunction;
-import java.util.function.LongPredicate;
-import java.util.function.LongToDoubleFunction;
-import java.util.function.LongToIntFunction;
-import java.util.function.LongUnaryOperator;
-import java.util.function.ObjDoubleConsumer;
-import java.util.function.ObjIntConsumer;
-import java.util.function.ObjLongConsumer;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-import java.util.function.ToDoubleFunction;
-
-import java.util.function.ToIntFunction;
-import java.util.function.ToLongFunction;
-
-import static java.util.stream.Collectors.*;
-
-public final class DefaultMethodStreams {
-
- static {
- // Verify that default methods are not overridden
- verify(DefaultMethodRefStream.class);
- verify(DefaultMethodIntStream.class);
- verify(DefaultMethodLongStream.class);
- verify(DefaultMethodDoubleStream.class);
- }
-
- static void verify(Class<?> del) {
- // Find the stream interface
- Class<?> s = Stream.of(del.getInterfaces())
- .filter(c -> BaseStream.class.isAssignableFrom(c))
- .findFirst().get();
-
- // Get all default methods on the stream class
- Set<String> dms = Stream.of(s.getMethods())
- .filter(m -> !Modifier.isStatic(m.getModifiers()))
- .filter(m -> !m.isBridge())
- .filter(Method::isDefault)
- .map(Method::getName)
- .collect(toSet());
-
- // Get all methods on the delegating class
- Set<String> ims = Stream.of(del.getMethods())
- .filter(m -> !Modifier.isStatic(m.getModifiers()))
- .filter(m -> m.getDeclaringClass() == del)
- .map(Method::getName)
- .collect(toSet());
-
- if (ims.stream().anyMatch(dms::contains)) {
- throw new AssertionError(String.format("%s overrides default methods of %s\n", del, s));
- }
- }
-
- /**
- * Creates a stream that for the next operation either delegates to
- * a default method on {@link Stream}, if present for that operation,
- * otherwise delegates to an underlying stream.
- *
- * @param s the underlying stream to be delegated to for non-default
- * methods.
- * @param <T> the type of the stream elements
- * @return the delegating stream
- */
- public static <T> Stream<T> delegateTo(Stream<T> s) {
- return new DefaultMethodRefStream<>(s);
- }
-
- /**
- * Creates a stream that for the next operation either delegates to
- * a default method on {@link IntStream}, if present for that operation,
- * otherwise delegates to an underlying stream.
- *
- * @param s the underlying stream to be delegated to for non-default
- * methods.
- * @return the delegating stream
- */
- public static IntStream delegateTo(IntStream s) {
- return new DefaultMethodIntStream(s);
- }
-
- /**
- * Creates a stream that for the next operation either delegates to
- * a default method on {@link LongStream}, if present for that operation,
- * otherwise delegates to an underlying stream.
- *
- * @param s the underlying stream to be delegated to for non-default
- * methods.
- * @return the delegating stream
- */
- public static LongStream delegateTo(LongStream s) {
- return new DefaultMethodLongStream(s);
- }
-
- /**
- * Creates a stream that for the next operation either delegates to
- * a default method on {@link DoubleStream}, if present for that operation,
- * otherwise delegates to an underlying stream.
- *
- * @param s the underlying stream to be delegated to for non-default
- * methods.
- * @return the delegating stream
- */
- public static DoubleStream delegateTo(DoubleStream s) {
- return new DefaultMethodDoubleStream(s);
- }
-
- /**
- * A stream that delegates the next operation to a default method, if
- * present, or to the same operation of an underlying stream.
- *
- * @param <T> the type of the stream elements
- */
- static final class DefaultMethodRefStream<T> implements Stream<T> {
- final Stream<T> s;
-
- DefaultMethodRefStream(Stream<T> s) {
- this.s = s;
- }
-
-
- // Delegating non-default methods
-
- @Override
- public Stream<T> filter(Predicate<? super T> predicate) {
- return s.filter(predicate);
- }
-
- @Override
- public <R> Stream<R> map(Function<? super T, ? extends R> mapper) {
- return s.map(mapper);
- }
-
- @Override
- public IntStream mapToInt(ToIntFunction<? super T> mapper) {
- return s.mapToInt(mapper);
- }
-
- @Override
- public LongStream mapToLong(ToLongFunction<? super T> mapper) {
- return s.mapToLong(mapper);
- }
-
- @Override
- public DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper) {
- return s.mapToDouble(mapper);
- }
-
- @Override
- public <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper) {
- return s.flatMap(mapper);
- }
-
- @Override
- public IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper) {
- return s.flatMapToInt(mapper);
- }
-
- @Override
- public LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper) {
- return s.flatMapToLong(mapper);
- }
-
- @Override
- public DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper) {
- return s.flatMapToDouble(mapper);
- }
-
- @Override
- public Stream<T> distinct() {
- return s.distinct();
- }
-
- @Override
- public Stream<T> sorted() {
- return s.sorted();
- }
-
- @Override
- public Stream<T> sorted(Comparator<? super T> comparator) {
- return s.sorted(comparator);
- }
-
- @Override
- public Stream<T> peek(Consumer<? super T> action) {
- return s.peek(action);
- }
-
- @Override
- public Stream<T> limit(long maxSize) {
- return s.limit(maxSize);
- }
-
- @Override
- public Stream<T> skip(long n) {
- return s.skip(n);
- }
-
- @Override
- public void forEach(Consumer<? super T> action) {
- s.forEach(action);
- }
-
- @Override
- public void forEachOrdered(Consumer<? super T> action) {
- s.forEachOrdered(action);
- }
-
- @Override
- public Object[] toArray() {
- return s.toArray();
- }
-
- @Override
- public <A> A[] toArray(IntFunction<A[]> generator) {
- return s.toArray(generator);
- }
-
- @Override
- public T reduce(T identity, BinaryOperator<T> accumulator) {
- return s.reduce(identity, accumulator);
- }
-
- @Override
- public Optional<T> reduce(BinaryOperator<T> accumulator) {
- return s.reduce(accumulator);
- }
-
- @Override
- public <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner) {
- return s.reduce(identity, accumulator, combiner);
- }
-
- @Override
- public <R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner) {
- return s.collect(supplier, accumulator, combiner);
- }
-
- @Override
- public <R, A> R collect(Collector<? super T, A, R> collector) {
- return s.collect(collector);
- }
-
- @Override
- public Optional<T> min(Comparator<? super T> comparator) {
- return s.min(comparator);
- }
-
- @Override
- public Optional<T> max(Comparator<? super T> comparator) {
- return s.max(comparator);
- }
-
- @Override
- public long count() {
- return s.count();
- }
-
- @Override
- public boolean anyMatch(Predicate<? super T> predicate) {
- return s.anyMatch(predicate);
- }
-
- @Override
- public boolean allMatch(Predicate<? super T> predicate) {
- return s.allMatch(predicate);
- }
-
- @Override
- public boolean noneMatch(Predicate<? super T> predicate) {
- return s.noneMatch(predicate);
- }
-
- @Override
- public Optional<T> findFirst() {
- return s.findFirst();
- }
-
- @Override
- public Optional<T> findAny() {
- return s.findAny();
- }
-
- @Override
- public Iterator<T> iterator() {
- return s.iterator();
- }
-
- @Override
- public Spliterator<T> spliterator() {
- return s.spliterator();
- }
-
- @Override
- public boolean isParallel() {
- return s.isParallel();
- }
-
- @Override
- public Stream<T> sequential() {
- return s.sequential();
- }
-
- @Override
- public Stream<T> parallel() {
- return s.parallel();
- }
-
- @Override
- public Stream<T> unordered() {
- return s.unordered();
- }
-
- @Override
- public Stream<T> onClose(Runnable closeHandler) {
- return s.onClose(closeHandler);
- }
-
- @Override
- public void close() {
- s.close();
- }
- }
-
- static final class DefaultMethodIntStream implements IntStream {
- final IntStream s;
-
- public DefaultMethodIntStream(IntStream s) {
- this.s = s;
- }
-
-
- // Delegating non-default methods
-
- @Override
- public IntStream filter(IntPredicate predicate) {
- return s.filter(predicate);
- }
-
- @Override
- public IntStream map(IntUnaryOperator mapper) {
- return s.map(mapper);
- }
-
- @Override
- public <U> Stream<U> mapToObj(IntFunction<? extends U> mapper) {
- return s.mapToObj(mapper);
- }
-
- @Override
- public LongStream mapToLong(IntToLongFunction mapper) {
- return s.mapToLong(mapper);
- }
-
- @Override
- public DoubleStream mapToDouble(IntToDoubleFunction mapper) {
- return s.mapToDouble(mapper);
- }
-
- @Override
- public IntStream flatMap(IntFunction<? extends IntStream> mapper) {
- return s.flatMap(mapper);
- }
-
- @Override
- public IntStream distinct() {
- return s.distinct();
- }
-
- @Override
- public IntStream sorted() {
- return s.sorted();
- }
-
- @Override
- public IntStream peek(IntConsumer action) {
- return s.peek(action);
- }
-
- @Override
- public IntStream limit(long maxSize) {
- return s.limit(maxSize);
- }
-
- @Override
- public IntStream skip(long n) {
- return s.skip(n);
- }
-
- @Override
- public void forEach(IntConsumer action) {
- s.forEach(action);
- }
-
- @Override
- public void forEachOrdered(IntConsumer action) {
- s.forEachOrdered(action);
- }
-
- @Override
- public int[] toArray() {
- return s.toArray();
- }
-
- @Override
- public int reduce(int identity, IntBinaryOperator op) {
- return s.reduce(identity, op);
- }
-
- @Override
- public OptionalInt reduce(IntBinaryOperator op) {
- return s.reduce(op);
- }
-
- @Override
- public <R> R collect(Supplier<R> supplier, ObjIntConsumer<R> accumulator, BiConsumer<R, R> combiner) {
- return s.collect(supplier, accumulator, combiner);
- }
-
- @Override
- public int sum() {
- return s.sum();
- }
-
- @Override
- public OptionalInt min() {
- return s.min();
- }
-
- @Override
- public OptionalInt max() {
- return s.max();
- }
-
- @Override
- public long count() {
- return s.count();
- }
-
- @Override
- public OptionalDouble average() {
- return s.average();
- }
-
- @Override
- public IntSummaryStatistics summaryStatistics() {
- return s.summaryStatistics();
- }
-
- @Override
- public boolean anyMatch(IntPredicate predicate) {
- return s.anyMatch(predicate);
- }
-
- @Override
- public boolean allMatch(IntPredicate predicate) {
- return s.allMatch(predicate);
- }
-
- @Override
- public boolean noneMatch(IntPredicate predicate) {
- return s.noneMatch(predicate);
- }
-
- @Override
- public OptionalInt findFirst() {
- return s.findFirst();
- }
-
- @Override
- public OptionalInt findAny() {
- return s.findAny();
- }
-
- @Override
- public LongStream asLongStream() {
- return s.asLongStream();
- }
-
- @Override
- public DoubleStream asDoubleStream() {
- return s.asDoubleStream();
- }
-
- @Override
- public Stream<Integer> boxed() {
- return s.boxed();
- }
-
- @Override
- public IntStream sequential() {
- return s.sequential();
- }
-
- @Override
- public IntStream parallel() {
- return s.parallel();
- }
-
- @Override
- public PrimitiveIterator.OfInt iterator() {
- return s.iterator();
- }
-
- @Override
- public Spliterator.OfInt spliterator() {
- return s.spliterator();
- }
-
- @Override
- public boolean isParallel() {
- return s.isParallel();
- }
-
- @Override
- public IntStream unordered() {
- return s.unordered();
- }
-
- @Override
- public IntStream onClose(Runnable closeHandler) {
- return s.onClose(closeHandler);
- }
-
- @Override
- public void close() {
- s.close();
- }
- }
-
- static final class DefaultMethodLongStream implements LongStream {
- final LongStream s;
-
- public DefaultMethodLongStream(LongStream s) {
- this.s = s;
- }
-
-
- // Delegating non-default methods
-
- @Override
- public void forEach(LongConsumer action) {
- s.forEach(action);
- }
-
- @Override
- public LongStream filter(LongPredicate predicate) {
- return s.filter(predicate);
- }
-
- @Override
- public LongStream map(LongUnaryOperator mapper) {
- return s.map(mapper);
- }
-
- @Override
- public <U> Stream<U> mapToObj(LongFunction<? extends U> mapper) {
- return s.mapToObj(mapper);
- }
-
- @Override
- public IntStream mapToInt(LongToIntFunction mapper) {
- return s.mapToInt(mapper);
- }
-
- @Override
- public DoubleStream mapToDouble(LongToDoubleFunction mapper) {
- return s.mapToDouble(mapper);
- }
-
- @Override
- public LongStream flatMap(LongFunction<? extends LongStream> mapper) {
- return s.flatMap(mapper);
- }
-
- @Override
- public LongStream distinct() {
- return s.distinct();
- }
-
- @Override
- public LongStream sorted() {
- return s.sorted();
- }
-
- @Override
- public LongStream peek(LongConsumer action) {
- return s.peek(action);
- }
-
- @Override
- public LongStream limit(long maxSize) {
- return s.limit(maxSize);
- }
-
- @Override
- public LongStream skip(long n) {
- return s.skip(n);
- }
-
- @Override
- public void forEachOrdered(LongConsumer action) {
- s.forEachOrdered(action);
- }
-
- @Override
- public long[] toArray() {
- return s.toArray();
- }
-
- @Override
- public long reduce(long identity, LongBinaryOperator op) {
- return s.reduce(identity, op);
- }
-
- @Override
- public OptionalLong reduce(LongBinaryOperator op) {
- return s.reduce(op);
- }
-
- @Override
- public <R> R collect(Supplier<R> supplier, ObjLongConsumer<R> accumulator, BiConsumer<R, R> combiner) {
- return s.collect(supplier, accumulator, combiner);
- }
-
- @Override
- public long sum() {
- return s.sum();
- }
-
- @Override
- public OptionalLong min() {
- return s.min();
- }
-
- @Override
- public OptionalLong max() {
- return s.max();
- }
-
- @Override
- public long count() {
- return s.count();
- }
-
- @Override
- public OptionalDouble average() {
- return s.average();
- }
-
- @Override
- public LongSummaryStatistics summaryStatistics() {
- return s.summaryStatistics();
- }
-
- @Override
- public boolean anyMatch(LongPredicate predicate) {
- return s.anyMatch(predicate);
- }
-
- @Override
- public boolean allMatch(LongPredicate predicate) {
- return s.allMatch(predicate);
- }
-
- @Override
- public boolean noneMatch(LongPredicate predicate) {
- return s.noneMatch(predicate);
- }
-
- @Override
- public OptionalLong findFirst() {
- return s.findFirst();
- }
-
- @Override
- public OptionalLong findAny() {
- return s.findAny();
- }
-
- @Override
- public DoubleStream asDoubleStream() {
- return s.asDoubleStream();
- }
-
- @Override
- public Stream<Long> boxed() {
- return s.boxed();
- }
-
- @Override
- public LongStream sequential() {
- return s.sequential();
- }
-
- @Override
- public LongStream parallel() {
- return s.parallel();
- }
-
- @Override
- public PrimitiveIterator.OfLong iterator() {
- return s.iterator();
- }
-
- @Override
- public Spliterator.OfLong spliterator() {
- return s.spliterator();
- }
-
- @Override
- public boolean isParallel() {
- return s.isParallel();
- }
-
- @Override
- public LongStream unordered() {
- return s.unordered();
- }
-
- @Override
- public LongStream onClose(Runnable closeHandler) {
- return s.onClose(closeHandler);
- }
-
- @Override
- public void close() {
- s.close();
- }
- }
-
- static final class DefaultMethodDoubleStream implements DoubleStream {
- final DoubleStream s;
-
- public DefaultMethodDoubleStream(DoubleStream s) {
- this.s = s;
- }
-
- @Override
- public DoubleStream filter(DoublePredicate predicate) {
- return s.filter(predicate);
- }
-
- @Override
- public DoubleStream map(DoubleUnaryOperator mapper) {
- return s.map(mapper);
- }
-
- @Override
- public <U> Stream<U> mapToObj(DoubleFunction<? extends U> mapper) {
- return s.mapToObj(mapper);
- }
-
- @Override
- public IntStream mapToInt(DoubleToIntFunction mapper) {
- return s.mapToInt(mapper);
- }
-
- @Override
- public LongStream mapToLong(DoubleToLongFunction mapper) {
- return s.mapToLong(mapper);
- }
-
- @Override
- public DoubleStream flatMap(DoubleFunction<? extends DoubleStream> mapper) {
- return s.flatMap(mapper);
- }
-
- @Override
- public DoubleStream distinct() {
- return s.distinct();
- }
-
- @Override
- public DoubleStream sorted() {
- return s.sorted();
- }
-
- @Override
- public DoubleStream peek(DoubleConsumer action) {
- return s.peek(action);
- }
-
- @Override
- public DoubleStream limit(long maxSize) {
- return s.limit(maxSize);
- }
-
- @Override
- public DoubleStream skip(long n) {
- return s.skip(n);
- }
-
- @Override
- public void forEach(DoubleConsumer action) {
- s.forEach(action);
- }
-
- @Override
- public void forEachOrdered(DoubleConsumer action) {
- s.forEachOrdered(action);
- }
-
- @Override
- public double[] toArray() {
- return s.toArray();
- }
-
- @Override
- public double reduce(double identity, DoubleBinaryOperator op) {
- return s.reduce(identity, op);
- }
-
- @Override
- public OptionalDouble reduce(DoubleBinaryOperator op) {
- return s.reduce(op);
- }
-
- @Override
- public <R> R collect(Supplier<R> supplier, ObjDoubleConsumer<R> accumulator, BiConsumer<R, R> combiner) {
- return s.collect(supplier, accumulator, combiner);
- }
-
- @Override
- public double sum() {
- return s.sum();
- }
-
- @Override
- public OptionalDouble min() {
- return s.min();
- }
-
- @Override
- public OptionalDouble max() {
- return s.max();
- }
-
- @Override
- public long count() {
- return s.count();
- }
-
- @Override
- public OptionalDouble average() {
- return s.average();
- }
-
- @Override
- public DoubleSummaryStatistics summaryStatistics() {
- return s.summaryStatistics();
- }
-
- @Override
- public boolean anyMatch(DoublePredicate predicate) {
- return s.anyMatch(predicate);
- }
-
- @Override
- public boolean allMatch(DoublePredicate predicate) {
- return s.allMatch(predicate);
- }
-
- @Override
- public boolean noneMatch(DoublePredicate predicate) {
- return s.noneMatch(predicate);
- }
-
- @Override
- public OptionalDouble findFirst() {
- return s.findFirst();
- }
-
- @Override
- public OptionalDouble findAny() {
- return s.findAny();
- }
-
- @Override
- public Stream<Double> boxed() {
- return s.boxed();
- }
-
- @Override
- public DoubleStream sequential() {
- return s.sequential();
- }
-
- @Override
- public DoubleStream parallel() {
- return s.parallel();
- }
-
- @Override
- public PrimitiveIterator.OfDouble iterator() {
- return s.iterator();
- }
-
- @Override
- public Spliterator.OfDouble spliterator() {
- return s.spliterator();
- }
-
- @Override
- public boolean isParallel() {
- return s.isParallel();
- }
-
- @Override
- public DoubleStream unordered() {
- return s.unordered();
- }
-
- @Override
- public DoubleStream onClose(Runnable closeHandler) {
- return s.onClose(closeHandler);
- }
-
- @Override
- public void close() {
- s.close();
- }
- }
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/DoubleStreamTestDataProvider.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,144 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import org.testng.annotations.DataProvider;
-
-import java.util.*;
-import java.util.Spliterators;
-import java.util.function.Supplier;
-
-/** TestNG DataProvider for double-valued streams */
-public class DoubleStreamTestDataProvider {
- private static final double[] to0 = new double[0];
- private static final double[] to1 = new double[1];
- private static final double[] to10 = new double[10];
- private static final double[] to100 = new double[100];
- private static final double[] to1000 = new double[1000];
- private static final double[] reversed = new double[100];
- private static final double[] ones = new double[100];
- private static final double[] twice = new double[200];
- private static final double[] pseudoRandom;
-
- private static final Object[][] testData;
- private static final Object[][] spliteratorTestData;
-
- static {
- double[][] arrays = {to0, to1, to10, to100, to1000};
- for (double[] arr : arrays) {
- for (int i = 0; i < arr.length; i++) {
- arr[i] = i;
- }
- }
- for (int i = 0; i < reversed.length; i++) {
- reversed[i] = reversed.length - i;
- }
- for (int i = 0; i < ones.length; i++) {
- ones[i] = 1;
- }
- System.arraycopy(to100, 0, twice, 0, to100.length);
- System.arraycopy(to100, 0, twice, to100.length, to100.length);
- pseudoRandom = new double[LambdaTestHelpers.LONG_STRING.length()];
- for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
- pseudoRandom[i] = (double) LambdaTestHelpers.LONG_STRING.charAt(i);
- }
- }
-
- static final Object[][] arrays = {
- {"empty", to0},
- {"0..1", to1},
- {"0..10", to10},
- {"0..100", to100},
- {"0..1000", to1000},
- {"100x[1]", ones},
- {"2x[0..100]", twice},
- {"reverse 0..100", reversed},
- {"pseudorandom", pseudoRandom}
- };
-
- static {
- {
- List<Object[]> list = new ArrayList<>();
- for (Object[] data : arrays) {
- final Object name = data[0];
- final double[] doubles = (double[]) data[1];
-
- list.add(new Object[]{"array:" + name,
- TestData.Factory.ofArray("array:" + name, doubles)});
-
- SpinedBuffer.OfDouble isl = new SpinedBuffer.OfDouble();
- for (double i : doubles) {
- isl.accept(i);
- }
- list.add(new Object[]{"SpinedList:" + name,
- TestData.Factory.ofSpinedBuffer("SpinedList:" + name, isl)});
- }
- testData = list.toArray(new Object[0][]);
- }
-
- {
- List<Object[]> spliterators = new ArrayList<>();
- for (Object[] data : arrays) {
- final Object name = data[0];
- final double[] doubles = (double[]) data[1];
-
- SpinedBuffer.OfDouble isl = new SpinedBuffer.OfDouble();
- for (double i : doubles) {
- isl.accept(i);
- }
-
- spliterators.add(splitDescr("Arrays.s(array):" + name,
- () -> Arrays.spliterator(doubles)));
- spliterators.add(splitDescr("Arrays.s(array,o,l):" + name,
- () -> Arrays.spliterator(doubles, 0, doubles.length / 2)));
-
- spliterators.add(splitDescr("SpinedBuffer.s():" + name,
- () -> isl.spliterator()));
-
- spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator(), size):" + name,
- () -> Spliterators.spliterator(isl.iterator(), doubles.length, 0)));
- spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator()):" + name,
- () -> Spliterators.spliteratorUnknownSize(isl.iterator(), 0)));
- // Need more!
- }
- spliteratorTestData = spliterators.toArray(new Object[0][]);
- }
-
- }
-
- static <T> Object[] splitDescr(String description, Supplier<Spliterator.OfDouble> s) {
- return new Object[] { description, s };
- }
-
- // Return an array of ( String name, DoubleStreamTestData )
- @DataProvider(name = "DoubleStreamTestData")
- public static Object[][] makeDoubleStreamTestData() {
- return testData;
- }
-
- // returns an array of (String name, Supplier<PrimitiveSpliterator<Double>>)
- @DataProvider(name = "DoubleSpliterator")
- public static Object[][] spliteratorProvider() {
- return spliteratorTestData;
- }
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/DoubleStreamTestScenario.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,232 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.PrimitiveIterator;
-import java.util.Set;
-import java.util.Spliterator;
-import java.util.function.Consumer;
-import java.util.function.DoubleConsumer;
-import java.util.function.Function;
-
-/**
- * Test scenarios for double streams.
- *
- * Each scenario is provided with a data source, a function that maps a fresh
- * stream (as provided by the data source) to a new stream, and a sink to
- * receive results. Each scenario describes a different way of computing the
- * stream contents. The test driver will ensure that all scenarios produce
- * the same output (modulo allowable differences in ordering).
- */
-@SuppressWarnings({"rawtypes", "unchecked"})
-public enum DoubleStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
-
- STREAM_FOR_EACH(false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
- DoubleStream s = m.apply(source);
- if (s.isParallel()) {
- s = s.sequential();
- }
- s.forEach(b);
- }
- },
-
- STREAM_TO_ARRAY(false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
- for (double t : m.apply(source).toArray()) {
- b.accept(t);
- }
- }
- },
-
- STREAM_ITERATOR(false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
- for (PrimitiveIterator.OfDouble seqIter = m.apply(source).iterator(); seqIter.hasNext(); )
- b.accept(seqIter.nextDouble());
- }
- },
-
- // Wrap as stream, and spliterate then iterate in pull mode
- STREAM_SPLITERATOR(false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
- for (Spliterator.OfDouble spl = m.apply(source).spliterator(); spl.tryAdvance(b); ) {
- }
- }
- },
-
- // Wrap as stream, spliterate, then split a few times mixing advances with forEach
- STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
- SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(source).spliterator());
- }
- },
-
- // Wrap as stream, and spliterate then iterate in pull mode
- STREAM_SPLITERATOR_FOREACH(false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
- m.apply(source).spliterator().forEachRemaining(b);
- }
- },
-
- PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
- m.apply(source).sequential().forEach(b);
- }
- },
-
- // Wrap as parallel stream + forEachOrdered
- PAR_STREAM_FOR_EACH_ORDERED(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
- // @@@ Want to explicitly select ordered equalator
- m.apply(source).forEachOrdered(b);
- }
- },
-
- // Wrap as stream, and spliterate then iterate sequentially
- PAR_STREAM_SPLITERATOR(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
- for (Spliterator.OfDouble spl = m.apply(source).spliterator(); spl.tryAdvance(b); ) {
- }
- }
- },
-
- // Wrap as stream, and spliterate then iterate sequentially
- PAR_STREAM_SPLITERATOR_FOREACH(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
- m.apply(source).spliterator().forEachRemaining(b);
- }
- },
-
- PAR_STREAM_TO_ARRAY(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
- for (double t : m.apply(source).toArray())
- b.accept(t);
- }
- },
-
- // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
- PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
- DoubleStream s = m.apply(source);
- Spliterator.OfDouble sp = s.spliterator();
- DoubleStream ss = StreamSupport.doubleStream(() -> sp,
- StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
- | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED), true);
- for (double t : ss.toArray())
- b.accept(t);
- }
- },
-
- PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
- S_IN pipe1 = (S_IN) OpTestCase.chain(source,
- new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
- DoubleStream pipe2 = m.apply(pipe1);
-
- for (double t : pipe2.toArray())
- b.accept(t);
- }
- },
-
- // Wrap as parallel stream + forEach synchronizing
- PAR_STREAM_FOR_EACH(true, false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
- m.apply(source).forEach(e -> {
- synchronized (data) {
- b.accept(e);
- }
- });
- }
- },
-
- // Wrap as parallel stream + forEach synchronizing and clear SIZED flag
- PAR_STREAM_FOR_EACH_CLEAR_SIZED(true, false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
- S_IN pipe1 = (S_IN) OpTestCase.chain(source,
- new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
- m.apply(pipe1).forEach(e -> {
- synchronized (data) {
- b.accept(e);
- }
- });
- }
- },
- ;
-
- // The set of scenarios that clean the SIZED flag
- public static final Set<DoubleStreamTestScenario> CLEAR_SIZED_SCENARIOS = Collections.unmodifiableSet(
- EnumSet.of(PAR_STREAM_TO_ARRAY_CLEAR_SIZED, PAR_STREAM_FOR_EACH_CLEAR_SIZED));
-
- private boolean isParallel;
-
- private final boolean isOrdered;
-
- DoubleStreamTestScenario(boolean isParallel) {
- this(isParallel, true);
- }
-
- DoubleStreamTestScenario(boolean isParallel, boolean isOrdered) {
- this.isParallel = isParallel;
- this.isOrdered = isOrdered;
- }
-
- public StreamShape getShape() {
- return StreamShape.DOUBLE_VALUE;
- }
-
- public boolean isParallel() {
- return isParallel;
- }
-
- public boolean isOrdered() {
- return isOrdered;
- }
-
- public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
- void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
- try (S_IN source = getStream(data)) {
- run(data, source, (DoubleConsumer) b, (Function<S_IN, DoubleStream>) m);
- }
- }
-
- abstract <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, DoubleConsumer b, Function<S_IN, DoubleStream> m);
-
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/FlagDeclaringOp.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-/**
- * An operation that injects or clears flags but otherwise performs no operation on elements.
- */
-@SuppressWarnings({"rawtypes", "unchecked"})
-public class FlagDeclaringOp<T> implements StatelessTestOp<T, T> {
- private final int flags;
- private final StreamShape shape;
-
- public FlagDeclaringOp(int flags) {
- this(flags, StreamShape.REFERENCE);
- }
-
- public FlagDeclaringOp(int flags, StreamShape shape) {
- this.flags = flags;
- this.shape = shape;
- }
-
- @Override
- public StreamShape outputShape() {
- return shape;
- }
-
- @Override
- public StreamShape inputShape() {
- return shape;
- }
-
- @Override
- public int opGetFlags() {
- return flags;
- }
-
- @Override
- public Sink<T> opWrapSink(int flags, boolean parallel, Sink sink) {
- return sink;
- }
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/IntStreamTestDataProvider.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,158 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import org.testng.annotations.DataProvider;
-
-import java.util.*;
-import java.util.Spliterators;
-import java.util.function.Supplier;
-
-/** TestNG DataProvider for int-valued streams */
-public class IntStreamTestDataProvider {
- private static final int[] to0 = new int[0];
- private static final int[] to1 = new int[1];
- private static final int[] to10 = new int[10];
- private static final int[] to100 = new int[100];
- private static final int[] to1000 = new int[1000];
- private static final int[] reversed = new int[100];
- private static final int[] ones = new int[100];
- private static final int[] twice = new int[200];
- private static final int[] pseudoRandom;
-
- private static final Object[][] testData;
- private static final Object[][] spliteratorTestData;
-
- static {
- int[][] arrays = {to0, to1, to10, to100, to1000};
- for (int[] arr : arrays) {
- for (int i = 0; i < arr.length; i++) {
- arr[i] = i;
- }
- }
- for (int i = 0; i < reversed.length; i++) {
- reversed[i] = reversed.length - i;
- }
- for (int i = 0; i < ones.length; i++) {
- ones[i] = 1;
- }
- System.arraycopy(to100, 0, twice, 0, to100.length);
- System.arraycopy(to100, 0, twice, to100.length, to100.length);
- pseudoRandom = new int[LambdaTestHelpers.LONG_STRING.length()];
- for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
- pseudoRandom[i] = (int) LambdaTestHelpers.LONG_STRING.charAt(i);
- }
- }
-
- static final Object[][] arrays = {
- {"empty", to0},
- {"0..1", to1},
- {"0..10", to10},
- {"0..100", to100},
- {"0..1000", to1000},
- {"100x[1]", ones},
- {"2x[0..100]", twice},
- {"reverse 0..100", reversed},
- {"pseudorandom", pseudoRandom}
- };
-
- static {
- {
- List<Object[]> list = new ArrayList<>();
- for (Object[] data : arrays) {
- final Object name = data[0];
- final int[] ints = (int[]) data[1];
-
- list.add(new Object[]{"array:" +
- name, TestData.Factory.ofArray("array:" + name, ints)});
-
- SpinedBuffer.OfInt isl = new SpinedBuffer.OfInt();
- for (int i : ints) {
- isl.accept(i);
- }
- list.add(new Object[]{"SpinedList:" + name,
- TestData.Factory.ofSpinedBuffer("SpinedList:" + name, isl)});
-
- list.add(streamDataDescr("IntStream.intRange(0,l): " + ints.length,
- () -> IntStream.range(0, ints.length)));
- list.add(streamDataDescr("IntStream.rangeClosed(0,l): " + ints.length,
- () -> IntStream.rangeClosed(0, ints.length)));
- }
- testData = list.toArray(new Object[0][]);
- }
-
- {
- List<Object[]> spliterators = new ArrayList<>();
- for (Object[] data : arrays) {
- final Object name = data[0];
- final int[] ints = (int[]) data[1];
-
- SpinedBuffer.OfInt isl = new SpinedBuffer.OfInt();
- for (int i : ints) {
- isl.accept(i);
- }
-
- spliterators.add(splitDescr("Arrays.s(array):" + name,
- () -> Arrays.spliterator(ints)));
- spliterators.add(splitDescr("Arrays.s(array,o,l):" + name,
- () -> Arrays.spliterator(ints, 0, ints.length / 2)));
-
- spliterators.add(splitDescr("SpinedBuffer.s():" + name,
- () -> isl.spliterator()));
-
- spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator(), size):" + name,
- () -> Spliterators.spliterator(isl.iterator(), ints.length, 0)));
- spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator()):" + name,
- () -> Spliterators.spliteratorUnknownSize(isl.iterator(), 0)));
-
- spliterators.add(splitDescr("IntStream.intRange(0,l):" + name,
- () -> IntStream.range(0, ints.length).spliterator()));
- spliterators.add(splitDescr("IntStream.intRangeClosed(0,l):" + name,
- () -> IntStream.rangeClosed(0, ints.length).spliterator()));
- // Need more!
- }
- spliteratorTestData = spliterators.toArray(new Object[0][]);
- }
-
- }
-
- static <T> Object[] streamDataDescr(String description, Supplier<IntStream> s) {
- return new Object[] { description, TestData.Factory.ofIntSupplier(description, s) };
- }
-
- static <T> Object[] splitDescr(String description, Supplier<Spliterator.OfInt> s) {
- return new Object[] { description, s };
- }
-
- // Return an array of ( String name, IntStreamTestData )
- @DataProvider(name = "IntStreamTestData")
- public static Object[][] makeIntStreamTestData() {
- return testData;
- }
-
- // returns an array of (String name, Supplier<PrimitiveSpliterator<Integer>>)
- @DataProvider(name = "IntSpliterator")
- public static Object[][] spliteratorProvider() {
- return spliteratorTestData;
- }
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/IntStreamTestScenario.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,233 +0,0 @@
-/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.PrimitiveIterator;
-import java.util.Set;
-import java.util.Spliterator;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.IntConsumer;
-
-/**
- * Test scenarios for int streams.
- *
- * Each scenario is provided with a data source, a function that maps a fresh
- * stream (as provided by the data source) to a new stream, and a sink to
- * receive results. Each scenario describes a different way of computing the
- * stream contents. The test driver will ensure that all scenarios produce
- * the same output (modulo allowable differences in ordering).
- */
-@SuppressWarnings({"rawtypes", "unchecked"})
-public enum IntStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
-
- STREAM_FOR_EACH(false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
- IntStream s = m.apply(source);
- if (s.isParallel()) {
- s = s.sequential();
- }
- s.forEach(b);
- }
- },
-
- STREAM_TO_ARRAY(false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
- for (int t : m.apply(source).toArray()) {
- b.accept(t);
- }
- }
- },
-
- STREAM_ITERATOR(false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
- for (PrimitiveIterator.OfInt seqIter = m.apply(source).iterator(); seqIter.hasNext(); )
- b.accept(seqIter.nextInt());
- }
- },
-
- // Wrap as stream, and spliterate then iterate in pull mode
- STREAM_SPLITERATOR(false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
- for (Spliterator.OfInt spl = m.apply(source).spliterator(); spl.tryAdvance(b); ) {
- }
- }
- },
-
- // Wrap as stream, spliterate, then split a few times mixing advances with forEach
- STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
- SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(source).spliterator());
- }
- },
-
- // Wrap as stream, and spliterate then iterate in pull mode
- STREAM_SPLITERATOR_FOREACH(false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
- m.apply(source).spliterator().forEachRemaining(b);
- }
- },
-
- PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
- m.apply(source).sequential().forEach(b);
- }
- },
-
- // Wrap as parallel stream + forEachOrdered
- PAR_STREAM_FOR_EACH_ORDERED(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
- // @@@ Want to explicitly select ordered equalator
- m.apply(source).forEachOrdered(b);
- }
- },
-
- // Wrap as stream, and spliterate then iterate sequentially
- PAR_STREAM_SPLITERATOR(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
- for (Spliterator.OfInt spl = m.apply(source).spliterator(); spl.tryAdvance(b); ) {
- }
- }
- },
-
- // Wrap as stream, and spliterate then iterate sequentially
- PAR_STREAM_SPLITERATOR_FOREACH(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
- m.apply(source).spliterator().forEachRemaining(b);
- }
- },
-
- PAR_STREAM_TO_ARRAY(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
- for (int t : m.apply(source).toArray())
- b.accept(t);
- }
- },
-
- // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
- PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
- IntStream s = m.apply(source);
- Spliterator.OfInt sp = s.spliterator();
- IntStream ss = StreamSupport.intStream(() -> sp,
- StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
- | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED),
- true);
- for (int t : ss.toArray())
- b.accept(t);
- }
- },
-
- PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
- S_IN pipe1 = (S_IN) OpTestCase.chain(source,
- new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
- IntStream pipe2 = m.apply(pipe1);
-
- for (int t : pipe2.toArray())
- b.accept(t);
- }
- },
-
- // Wrap as parallel stream + forEach synchronizing
- PAR_STREAM_FOR_EACH(true, false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
- m.apply(source).forEach(e -> {
- synchronized (data) {
- b.accept(e);
- }
- });
- }
- },
-
- // Wrap as parallel stream + forEach synchronizing and clear SIZED flag
- PAR_STREAM_FOR_EACH_CLEAR_SIZED(true, false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m) {
- S_IN pipe1 = (S_IN) OpTestCase.chain(source,
- new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
- m.apply(pipe1).forEach(e -> {
- synchronized (data) {
- b.accept(e);
- }
- });
- }
- },
- ;
-
- // The set of scenarios that clean the SIZED flag
- public static final Set<IntStreamTestScenario> CLEAR_SIZED_SCENARIOS = Collections.unmodifiableSet(
- EnumSet.of(PAR_STREAM_TO_ARRAY_CLEAR_SIZED, PAR_STREAM_FOR_EACH_CLEAR_SIZED));
-
- private final boolean isParallel;
-
- private final boolean isOrdered;
-
- IntStreamTestScenario(boolean isParallel) {
- this(isParallel, true);
- }
-
- IntStreamTestScenario(boolean isParallel, boolean isOrdered) {
- this.isParallel = isParallel;
- this.isOrdered = isOrdered;
- }
-
- public StreamShape getShape() {
- return StreamShape.INT_VALUE;
- }
-
- public boolean isParallel() {
- return isParallel;
- }
-
- public boolean isOrdered() {
- return isOrdered;
- }
-
- public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
- void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
- try (S_IN source = getStream(data)) {
- run(data, source, (IntConsumer) b, (Function<S_IN, IntStream>) m);
- }
- }
-
- abstract <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, IntConsumer b, Function<S_IN, IntStream> m);
-
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/IntermediateTestOp.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-/**
- * A base type for test operations
- */
-interface IntermediateTestOp<E_IN, E_OUT> {
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- public static<T> AbstractPipeline chain(AbstractPipeline upstream,
- IntermediateTestOp<?, T> op) {
- if (op instanceof StatelessTestOp)
- return StatelessTestOp.chain(upstream, (StatelessTestOp) op);
-
- if (op instanceof StatefulTestOp)
- return StatefulTestOp.chain(upstream, (StatefulTestOp) op);
-
- throw new IllegalStateException("Unknown test op type: " + op.getClass().getName());
- }
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/LambdaTestHelpers.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,462 +0,0 @@
-/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import java.util.*;
-import java.util.function.BiConsumer;
-import java.util.function.BiPredicate;
-import java.util.function.BinaryOperator;
-import java.util.function.Consumer;
-import java.util.function.DoubleBinaryOperator;
-import java.util.function.DoubleConsumer;
-import java.util.function.DoublePredicate;
-import java.util.function.Function;
-import java.util.function.IntBinaryOperator;
-import java.util.function.IntConsumer;
-import java.util.function.IntFunction;
-import java.util.function.IntPredicate;
-import java.util.function.IntUnaryOperator;
-import java.util.function.LongBinaryOperator;
-import java.util.function.LongConsumer;
-import java.util.function.LongPredicate;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-import java.util.function.ToDoubleFunction;
-import java.util.function.ToIntFunction;
-import java.util.function.ToLongFunction;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-
-/**
- * LambdaTestHelpers -- assertion methods and useful objects for lambda test cases
- */
-public class LambdaTestHelpers {
- public static final String LONG_STRING = "When in the Course of human events it becomes necessary for one people to dissolve the political bands which have connected them with another and to assume among the powers of the earth, the separate and equal station to which the Laws of Nature and of Nature's God entitle them, a decent respect to the opinions of mankind requires that they should declare the causes which impel them to the separation.";
-
- @SuppressWarnings("rawtypes")
- public static final Consumer bEmpty = x -> { };
- @SuppressWarnings("rawtypes")
- public static final IntConsumer bIntEmpty = x -> { };
- @SuppressWarnings("rawtypes")
- public static final BiConsumer bBiEmpty = (x,y) -> { };
- @SuppressWarnings("rawtypes")
- public static final Consumer bHashCode = x -> { Objects.hashCode(x); };
- @SuppressWarnings("rawtypes")
- public static final BiConsumer bBiHashCode = (x,y) -> { Objects.hash(x, y); };
- public static final Function<Integer, Integer> mZero = x -> 0;
- public static final Function<Integer, Integer> mId = x -> x;
- public static final Function<Integer, Integer> mDoubler = x -> x * 2;
- public static final Function<Integer, Stream<Integer>> mfId = e -> Collections.singletonList(e).stream();
- public static final Function<Integer, Stream<Integer>> mfNull = e -> Collections.<Integer>emptyList().stream();
- public static final Function<Integer, Stream<Integer>> mfLt = e -> {
- List<Integer> l = new ArrayList<>();
- for (int i=0; i<e; i++)
- l.add(i);
- return l.stream();
- };
- public static final ToIntFunction<Integer> imDoubler = x -> x * 2;
- public static final ToLongFunction<Long> lmDoubler = x -> x * 2;
- public static final ToDoubleFunction<Double> dmDoubler = x -> x * 2;
- public static final Predicate<Integer> pFalse = x -> false;
- public static final Predicate<Integer> pTrue = x -> true;
- public static final Predicate<Integer> pEven = x -> 0 == x % 2;
- public static final Predicate<Integer> pOdd = x -> 1 == x % 2;
- public static final IntPredicate ipFalse = x -> false;
- public static final IntPredicate ipTrue = x -> true;
- public static final IntPredicate ipEven = x -> 0 == x % 2;
- public static final IntPredicate ipOdd = x -> 1 == x % 2;
- public static final LongPredicate lpFalse = x -> false;
- public static final LongPredicate lpTrue = x -> true;
- public static final LongPredicate lpEven = x -> 0 == x % 2;
- public static final LongPredicate lpOdd = x -> 1 == x % 2;
- public static final DoublePredicate dpFalse = x -> false;
- public static final DoublePredicate dpTrue = x -> true;
- public static final DoublePredicate dpEven = x -> 0 == ((long) x) % 2;
- public static final DoublePredicate dpOdd = x -> 1 == ((long) x) % 2;
- public static final BinaryOperator<Integer> rPlus = (x, y) -> x+y;
- public static final BinaryOperator<Integer> rMax = (x, y) -> Math.max(x, y);
- public static final BinaryOperator<Integer> rMin = (x, y) -> Math.min(x,y);
- public static final IntBinaryOperator irPlus = (x, y) -> x+y;
- public static final IntBinaryOperator irMax = (x, y) -> Math.max(x, y);
- public static final IntBinaryOperator irMin = (x, y) -> Math.min(x,y);
- public static final IntUnaryOperator irDoubler = x -> x * 2;
- public static final LongBinaryOperator lrPlus = (x, y) -> x+y;
- public static final DoubleBinaryOperator drPlus = (x, y) -> x+y;
- public static final Comparator<Integer> cInteger = (a, b) -> Integer.compare(a, b);
- public static final BiPredicate<?, ?> bipFalse = (x, y) -> false;
- public static final BiPredicate<?, ?> bipTrue = (x, y) -> true;
- public static final BiPredicate<Integer, Integer> bipBothEven = (x, y) -> 0 == (x % 2 + y % 2);
- public static final BiPredicate<Integer, Integer> bipBothOdd = (x, y) -> 2 == (x % 2 + y % 2);
- public static final BiPredicate<?, ?> bipSameString = (x, y) -> String.valueOf(x).equals(String.valueOf(y));
-
- public static final IntFunction<Integer[]> integerArrayGenerator = s -> new Integer[s];
-
- public static final IntFunction<Object[]> objectArrayGenerator = s -> new Object[s];
-
- public static final Function<String, Stream<Character>> flattenChars = string -> {
- List<Character> l = new ArrayList<>();
- for (int i=0; i<string.length(); i++)
- l.add(string.charAt(i));
- return l.stream();
- };
-
- public static final Function<String, IntStream> flattenInt
- = string -> IntStream.range(0, string.length()).map(string::charAt);
-
- public static <T, R> Function<T, R> forPredicate(Predicate<? super T> predicate, R forTrue, R forFalse) {
- Objects.requireNonNull(predicate);
-
- return t -> predicate.test(t) ? forTrue : forFalse;
- }
-
- public static <T> Function<T, T> identity() {
- return t -> t;
- }
-
- public static<V, T, R> Function<V, R> compose(Function<? super T, ? extends R> after, Function<? super V, ? extends T> before) {
- Objects.requireNonNull(before);
- return (V v) -> after.apply(before.apply(v));
- }
-
- public static List<Integer> empty() {
- ArrayList<Integer> list = new ArrayList<>();
- list.add(null);
- return list;
- }
-
- public static List<Integer> countTo(int n) {
- return range(1, n);
- }
-
- public static List<Integer> range(int l, int u) {
- ArrayList<Integer> list = new ArrayList<>(u - l + 1);
- for (int i=l; i<=u; i++) {
- list.add(i);
- }
- return list;
- }
-
- public static List<Integer> repeat(int value, int n) {
- ArrayList<Integer> list = new ArrayList<>(n);
- for (int i=1; i<=n; i++) {
- list.add(value);
- }
- return list;
- }
-
- public static List<Double> asDoubles(List<Integer> integers) {
- ArrayList<Double> list = new ArrayList<>();
- for (Integer i : integers) {
- list.add((double) i);
- }
- return list;
- }
-
- public static List<Long> asLongs(List<Integer> integers) {
- ArrayList<Long> list = new ArrayList<>();
- for (Integer i : integers) {
- list.add((long) i);
- }
- return list;
- }
-
- public static void assertCountSum(Stream<? super Integer> it, int count, int sum) {
- assertCountSum(it.iterator(), count, sum);
- }
-
- public static void assertCountSum(Iterable<? super Integer> it, int count, int sum) {
- assertCountSum(it.iterator(), count, sum);
- }
-
- public static void assertCountSum(Iterator<? super Integer> it, int count, int sum) {
- int c = 0;
- int s = 0;
- while (it.hasNext()) {
- int i = (Integer) it.next();
- c++;
- s += i;
- }
-
- assertEquals(c, count);
- assertEquals(s, sum);
- }
-
- public static void assertConcat(Iterator<Character> it, String result) {
- StringBuilder sb = new StringBuilder();
- while (it.hasNext()) {
- sb.append(it.next());
- }
-
- assertEquals(result, sb.toString());
- }
-
- public static<T extends Comparable<? super T>> void assertSorted(Iterator<T> i) {
- i = toBoxedList(i).iterator();
-
- if (!i.hasNext())
- return;
- T last = i.next();
- while (i.hasNext()) {
- T t = i.next();
- assertTrue(last.compareTo(t) <= 0);
- assertTrue(t.compareTo(last) >= 0);
- last = t;
- }
- }
-
- public static<T> void assertSorted(Iterator<T> i, Comparator<? super T> comp) {
- if (i instanceof PrimitiveIterator.OfInt
- || i instanceof PrimitiveIterator.OfDouble
- || i instanceof PrimitiveIterator.OfLong) {
- i = toBoxedList(i).iterator();
- }
-
- if (!i.hasNext())
- return;
- T last = i.next();
- while (i.hasNext()) {
- T t = i.next();
- assertTrue(comp.compare(last, t) <= 0);
- assertTrue(comp.compare(t, last) >= 0);
- last = t;
- }
- }
-
- public static<T extends Comparable<? super T>> void assertSorted(Iterable<T> iter) {
- assertSorted(iter.iterator());
- }
-
- public static<T> void assertSorted(Iterable<T> iter, Comparator<? super T> comp) {
- assertSorted(iter.iterator(), comp);
- }
-
- public static <T> void assertUnique(Iterable<T> iter) {
- assertUnique(iter.iterator());
- }
-
- public static<T> void assertUnique(Iterator<T> iter) {
- if (!iter.hasNext()) {
- return;
- }
-
- if (iter instanceof PrimitiveIterator.OfInt
- || iter instanceof PrimitiveIterator.OfDouble
- || iter instanceof PrimitiveIterator.OfLong) {
- iter = toBoxedList(iter).iterator();
- }
-
- Set<T> uniq = new HashSet<>();
- while(iter.hasNext()) {
- T each = iter.next();
- assertTrue(!uniq.contains(each), "Not unique");
- uniq.add(each);
- }
- }
-
- public static<T> void assertContents(Iterable<T> actual, Iterable<T> expected) {
- if (actual instanceof Collection && expected instanceof Collection) {
- assertEquals(actual, expected);
- } else {
- assertContents(actual.iterator(), expected.iterator());
- }
- }
-
- public static<T> void assertContents(Iterator<T> actual, Iterator<T> expected) {
- assertEquals(toBoxedList(actual), toBoxedList(expected));
- }
-
- @SafeVarargs
- @SuppressWarnings("varargs")
- public static<T> void assertContents(Iterator<T> actual, T... expected) {
- assertContents(actual, Arrays.asList(expected).iterator());
- }
-
- /**
- * The all consuming consumer (rampant capitalist) that can accepting a reference or any primitive value.
- */
- private static interface OmnivorousConsumer<T>
- extends Consumer<T>, IntConsumer, LongConsumer, DoubleConsumer { }
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- public static<T> Consumer<T> toBoxingConsumer(Consumer<? super T> c) {
- return (Consumer<T>) new OmnivorousConsumer() {
- @Override
- public void accept(Object t) {
- c.accept((T) t);
- }
-
- @Override
- public void accept(int t) {
- accept((Object) t);
- }
-
- @Override
- public void accept(long t) {
- accept((Object) t);
- }
-
- @Override
- public void accept(double t) {
- accept((Object) t);
- }
- };
- }
-
- /**
- * Convert an iterator to a list using forEach with an implementation of
- * {@link java.util.stream.LambdaTestHelpers.OmnivorousConsumer}.
- *
- * This ensures equality comparisons for test results do not trip
- * the boxing trip-wires.
- */
- private static<T> List<T> toBoxedList(Iterator<T> it) {
- List<T> l = new ArrayList<>();
- it.forEachRemaining(toBoxingConsumer(l::add));
- return l;
- }
-
- /**
- * Convert a spliterator to a list using forEach with an implementation of
- * {@link java.util.stream.LambdaTestHelpers.OmnivorousConsumer}.
- *
- * This ensures equality comparisons for test results do not trip
- * the boxing trip-wires.
- */
- public static<T> List<T> toBoxedList(Spliterator<T> sp) {
- List<T> l = new ArrayList<>();
- sp.forEachRemaining(toBoxingConsumer(l::add));
- return l;
- }
-
- /**
- * Convert an iterator to a multi-set, represented as a Map, using forEach with an implementation of
- * {@link java.util.stream.LambdaTestHelpers.OmnivorousConsumer}.
- *
- * This ensures equality comparisons for test results do not trip
- * the boxing trip-wires.
- */
- @SuppressWarnings("unchecked")
- private static<T> Map<T, Integer> toBoxedMultiset(Iterator<T> it) {
- Map<Object, Integer> result = new HashMap<>();
-
- it.forEachRemaining(toBoxingConsumer(o -> {
- if (result.containsKey(o))
- result.put(o, result.get(o) + 1);
- else
- result.put(o, 1);
- }));
-
- return (Map<T, Integer>) result;
- }
-
- @SuppressWarnings("unchecked")
- public static<T> Map<T, Integer> toBoxedMultiset(Spliterator<T> it) {
- Map<Object, Integer> result = new HashMap<>();
-
- it.forEachRemaining(toBoxingConsumer(o -> {
- if (result.containsKey(o))
- result.put(o, result.get(o) + 1);
- else
- result.put(o, 1);
- }));
-
- return (Map<T, Integer>) result;
- }
-
- @SuppressWarnings("unchecked")
- public static void assertContentsEqual(Object a, Object b) {
- if (a instanceof Iterable && b instanceof Iterable)
- assertContents((Iterable) a, (Iterable) b);
- else
- assertEquals(a, b);
- }
-
- public static<T> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected) {
- assertContentsUnordered(actual.iterator(), expected.iterator());
- }
-
- public static<T> void assertContentsUnordered(Iterator<T> actual, Iterator<T> expected) {
- assertEquals(toBoxedMultiset(actual), toBoxedMultiset(expected));
- }
-
- public static void launderAssertion(Runnable r, Supplier<String> additionalInfo) {
- try {
- r.run();
- }
- catch (AssertionError ae) {
- AssertionError cloned = new AssertionError(ae.getMessage() + String.format("%n%s", additionalInfo.get()));
- cloned.setStackTrace(ae.getStackTrace());
- if (ae.getCause() != null)
- cloned.initCause(ae.getCause());
- throw cloned;
- }
- }
-
- public static <T, S extends BaseStream<T, S>>
- List<Function<S, S>> permuteStreamFunctions(List<Function<S, S>> opFunctions) {
- List<List<Function<S, S>>> opFunctionPermutations = perm(opFunctions);
-
- List<Function<S, S>> appliedFunctions = new ArrayList<>();
- for (List<Function<S, S>> fs : opFunctionPermutations) {
- Function<S, S> applied = s -> {
- for (Function<S, S> f : fs) {
- s = f.apply(s);
- }
- return s;
- };
- appliedFunctions.add(applied);
- }
-
- return appliedFunctions;
- }
-
- private static <T> List<T> sub(List<T> l, int index) {
- List<T> subL = new ArrayList<>(l);
- subL.remove(index);
- return subL;
- }
-
- public static <T> List<List<T>> perm(List<T> l) {
- List<List<T>> result = new ArrayList<>();
- for (int i = 0; i < l.size(); i++) {
- for (List<T> perm : perm(sub(l, i))) {
- perm.add(0, l.get(i));
- result.add(perm);
- }
- }
- result.add(new ArrayList<T>());
-
- return result;
- }
-
- public static String flagsToString(int flags) {
- StringJoiner sj = new StringJoiner(", ", "StreamOpFlag[", "]");
- if (StreamOpFlag.DISTINCT.isKnown(flags)) sj.add("IS_DISTINCT");
- if (StreamOpFlag.ORDERED.isKnown(flags)) sj.add("IS_ORDERED");
- if (StreamOpFlag.SIZED.isKnown(flags)) sj.add("IS_SIZED");
- if (StreamOpFlag.SORTED.isKnown(flags)) sj.add("IS_SORTED");
- if (StreamOpFlag.SHORT_CIRCUIT.isKnown(flags)) sj.add("IS_SHORT_CIRCUIT");
- return sj.toString();
- }
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/LambdaTestMode.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-/**
- * Runtime modes of test execution.
- */
-public enum LambdaTestMode {
- /**
- * Execution mode with no particular runtime constraints.
- */
- NORMAL,
-
- /**
- * Execution mode where tests are executed for testing lambda serialization
- * and deserialization.
- *
- * <p>This mode may be queried by tests or data supplied by data
- * providers, which cannot otherwise be assigned to the test group
- * <em>serialization-hostile</em>, to not execute or declare
- * serialization-hostile code or data.
- *
- * <p>This mode is enabled if the boolean system property
- * {@code org.openjdk.java.util.stream.sand.mode} is declared with a
- * {@code true} value.
- */
- SERIALIZATION;
-
- /**
- * {@code true} if tests are executed in the mode for testing lambda
- * Serialization ANd Deserialization (SAND).
- */
- private static final boolean IS_LAMBDA_SERIALIZATION_MODE =
- Boolean.getBoolean("org.openjdk.java.util.stream.sand.mode");
-
- /**
- *
- * @return the mode of test execution.
- */
- public static LambdaTestMode getMode() {
- return IS_LAMBDA_SERIALIZATION_MODE ? SERIALIZATION : NORMAL;
- }
-
- /**
- *
- * @return {@code true} if normal test mode.
- */
- public static boolean isNormalMode() {
- return getMode() == NORMAL;
- }
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/LoggingTestCase.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.testng.Assert;
-import org.testng.ITestResult;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-/**
- * LoggingTestCase
- *
- */
-@Test
-public class LoggingTestCase extends Assert {
- private Map<String, Object> context = new HashMap<>();
-
- @BeforeMethod
- public void before() {
- context.clear();
- }
-
- @AfterMethod
- public void after(ITestResult result) {
- if (!result.isSuccess()) {
- List<Object> list = new ArrayList<>();
- Collections.addAll(list, result.getParameters());
- list.add(context.toString());
- result.setParameters(list.toArray(new Object[list.size()]));
- }
- }
-
- protected void setContext(String key, Object value) {
- context.put(key, value);
- }
-
- protected void clearContext(String key) {
- context.remove(key);
- }
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/LongStreamTestDataProvider.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,158 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import org.testng.annotations.DataProvider;
-
-import java.util.*;
-import java.util.Spliterators;
-import java.util.function.Supplier;
-
-/** TestNG DataProvider for long-valued streams */
-public class LongStreamTestDataProvider {
- private static final long[] to0 = new long[0];
- private static final long[] to1 = new long[1];
- private static final long[] to10 = new long[10];
- private static final long[] to100 = new long[100];
- private static final long[] to1000 = new long[1000];
- private static final long[] reversed = new long[100];
- private static final long[] ones = new long[100];
- private static final long[] twice = new long[200];
- private static final long[] pseudoRandom;
-
- private static final Object[][] testData;
- private static final Object[][] spliteratorTestData;
-
- static {
- long[][] arrays = {to0, to1, to10, to100, to1000};
- for (long[] arr : arrays) {
- for (int i = 0; i < arr.length; i++) {
- arr[i] = i;
- }
- }
- for (int i = 0; i < reversed.length; i++) {
- reversed[i] = reversed.length - i;
- }
- for (int i = 0; i < ones.length; i++) {
- ones[i] = 1;
- }
- System.arraycopy(to100, 0, twice, 0, to100.length);
- System.arraycopy(to100, 0, twice, to100.length, to100.length);
- pseudoRandom = new long[LambdaTestHelpers.LONG_STRING.length()];
- for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
- pseudoRandom[i] = (long) LambdaTestHelpers.LONG_STRING.charAt(i);
- }
- }
-
- static final Object[][] arrays = {
- {"empty", to0},
- {"0..1", to1},
- {"0..10", to10},
- {"0..100", to100},
- {"0..1000", to1000},
- {"100x[1]", ones},
- {"2x[0..100]", twice},
- {"reverse 0..100", reversed},
- {"pseudorandom", pseudoRandom}
- };
-
- static {
- {
- List<Object[]> list = new ArrayList<>();
- for (Object[] data : arrays) {
- final Object name = data[0];
- final long[] longs = (long[]) data[1];
-
- list.add(new Object[]{"array:" + name,
- TestData.Factory.ofArray("array:" + name, longs)});
-
- SpinedBuffer.OfLong isl = new SpinedBuffer.OfLong();
- for (long i : longs) {
- isl.accept(i);
- }
- list.add(new Object[]{"SpinedList:" + name,
- TestData.Factory.ofSpinedBuffer("SpinedList:" + name, isl)});
-
- list.add(streamDataDescr("LongStream.longRange(0,l): " + longs.length,
- () -> LongStream.range(0, longs.length)));
- list.add(streamDataDescr("LongStream.longRangeClosed(0,l): " + longs.length,
- () -> LongStream.rangeClosed(0, longs.length)));
- }
- testData = list.toArray(new Object[0][]);
- }
-
- {
- List<Object[]> spliterators = new ArrayList<>();
- for (Object[] data : arrays) {
- final Object name = data[0];
- final long[] longs = (long[]) data[1];
-
- SpinedBuffer.OfLong isl = new SpinedBuffer.OfLong();
- for (long i : longs) {
- isl.accept(i);
- }
-
- spliterators.add(splitDescr("Arrays.s(array):" + name,
- () -> Arrays.spliterator(longs)));
- spliterators.add(splitDescr("Arrays.s(array,o,l):" + name,
- () -> Arrays.spliterator(longs, 0, longs.length / 2)));
-
- spliterators.add(splitDescr("SpinedBuffer.s():" + name,
- () -> isl.spliterator()));
-
- spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator(), size):" + name,
- () -> Spliterators.spliterator(isl.iterator(), longs.length, 0)));
- spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator()):" + name,
- () -> Spliterators.spliteratorUnknownSize(isl.iterator(), 0)));
-
- spliterators.add(splitDescr("LongStream.longRange(0,l):" + name,
- () -> LongStream.range(0, longs.length).spliterator()));
- spliterators.add(splitDescr("LongStream.longRangeClosed(0,l):" + name,
- () -> LongStream.rangeClosed(0, longs.length).spliterator()));
- // Need more!
- }
- spliteratorTestData = spliterators.toArray(new Object[0][]);
- }
-
- }
-
- static <T> Object[] streamDataDescr(String description, Supplier<LongStream> s) {
- return new Object[] { description, TestData.Factory.ofLongSupplier(description, s) };
- }
-
- static <T> Object[] splitDescr(String description, Supplier<Spliterator.OfLong> s) {
- return new Object[] { description, s };
- }
-
- // Return an array of ( String name, LongStreamTestData )
- @DataProvider(name = "LongStreamTestData")
- public static Object[][] makeLongStreamTestData() {
- return testData;
- }
-
- // returns an array of (String name, Supplier<PrimitiveSpliterator<Long>>)
- @DataProvider(name = "LongSpliterator")
- public static Object[][] spliteratorProvider() {
- return spliteratorTestData;
- }
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/LongStreamTestScenario.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,232 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.PrimitiveIterator;
-import java.util.Set;
-import java.util.Spliterator;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.LongConsumer;
-
-/**
- * Test scenarios for long streams.
- *
- * Each scenario is provided with a data source, a function that maps a fresh
- * stream (as provided by the data source) to a new stream, and a sink to
- * receive results. Each scenario describes a different way of computing the
- * stream contents. The test driver will ensure that all scenarios produce
- * the same output (modulo allowable differences in ordering).
- */
-@SuppressWarnings({"rawtypes", "unchecked"})
-public enum LongStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
-
- STREAM_FOR_EACH(false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
- LongStream s = m.apply(source);
- if (s.isParallel()) {
- s = s.sequential();
- }
- s.forEach(b);
- }
- },
-
- STREAM_TO_ARRAY(false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
- for (long t : m.apply(source).toArray()) {
- b.accept(t);
- }
- }
- },
-
- STREAM_ITERATOR(false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
- for (PrimitiveIterator.OfLong seqIter = m.apply(source).iterator(); seqIter.hasNext(); )
- b.accept(seqIter.nextLong());
- }
- },
-
- // Wrap as stream, and spliterate then iterate in pull mode
- STREAM_SPLITERATOR(false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
- for (Spliterator.OfLong spl = m.apply(source).spliterator(); spl.tryAdvance(b); ) {
- }
- }
- },
-
- // Wrap as stream, spliterate, then split a few times mixing advances with forEach
- STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
- SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(source).spliterator());
- }
- },
-
- // Wrap as stream, and spliterate then iterate in pull mode
- STREAM_SPLITERATOR_FOREACH(false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
- m.apply(source).spliterator().forEachRemaining(b);
- }
- },
-
- PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
- m.apply(source).sequential().forEach(b);
- }
- },
-
- // Wrap as parallel stream + forEachOrdered
- PAR_STREAM_FOR_EACH_ORDERED(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
- // @@@ Want to explicitly select ordered equalator
- m.apply(source).forEachOrdered(b);
- }
- },
-
- // Wrap as stream, and spliterate then iterate sequentially
- PAR_STREAM_SPLITERATOR(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
- for (Spliterator.OfLong spl = m.apply(source).spliterator(); spl.tryAdvance(b); ) {
- }
- }
- },
-
- // Wrap as stream, and spliterate then iterate sequentially
- PAR_STREAM_SPLITERATOR_FOREACH(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
- m.apply(source).spliterator().forEachRemaining(b);
- }
- },
-
- PAR_STREAM_TO_ARRAY(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
- for (long t : m.apply(source).toArray())
- b.accept(t);
- }
- },
-
- // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
- PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
- LongStream s = m.apply(source);
- Spliterator.OfLong sp = s.spliterator();
- LongStream ss = StreamSupport.longStream(() -> sp,
- StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
- | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED), true);
- for (long t : ss.toArray())
- b.accept(t);
- }
- },
-
- PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
- S_IN pipe1 = (S_IN) OpTestCase.chain(source,
- new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
- LongStream pipe2 = m.apply(pipe1);
-
- for (long t : pipe2.toArray())
- b.accept(t);
- }
- },
-
- // Wrap as parallel stream + forEach synchronizing
- PAR_STREAM_FOR_EACH(true, false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
- m.apply(source).forEach(e -> {
- synchronized (data) {
- b.accept(e);
- }
- });
- }
- },
-
- // Wrap as parallel stream + forEach synchronizing and clear SIZED flag
- PAR_STREAM_FOR_EACH_CLEAR_SIZED(true, false) {
- <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m) {
- S_IN pipe1 = (S_IN) OpTestCase.chain(source,
- new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
- m.apply(pipe1).forEach(e -> {
- synchronized (data) {
- b.accept(e);
- }
- });
- }
- },
- ;
-
- // The set of scenarios that clean the SIZED flag
- public static final Set<LongStreamTestScenario> CLEAR_SIZED_SCENARIOS = Collections.unmodifiableSet(
- EnumSet.of(PAR_STREAM_TO_ARRAY_CLEAR_SIZED, PAR_STREAM_FOR_EACH_CLEAR_SIZED));
-
- private boolean isParallel;
-
- private final boolean isOrdered;
-
- LongStreamTestScenario(boolean isParallel) {
- this(isParallel, true);
- }
-
- LongStreamTestScenario(boolean isParallel, boolean isOrdered) {
- this.isParallel = isParallel;
- this.isOrdered = isOrdered;
- }
-
- public StreamShape getShape() {
- return StreamShape.LONG_VALUE;
- }
-
- public boolean isParallel() {
- return isParallel;
- }
-
- public boolean isOrdered() {
- return isOrdered;
- }
-
- public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
- void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
- try (S_IN source = getStream(data)) {
- run(data, source, (LongConsumer) b, (Function<S_IN, LongStream>) m);
- }
- }
-
- abstract <T, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, LongConsumer b, Function<S_IN, LongStream> m);
-
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/OpTestCase.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,682 +0,0 @@
-/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumMap;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.Spliterator;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.function.Function;
-
-import org.testng.annotations.Test;
-
-/**
- * Base class for streams test cases. Provides 'exercise' methods for taking
- * lambdas that construct and modify streams, and evaluates them in different
- * ways and asserts that they produce equivalent results.
- */
-@Test
-public abstract class OpTestCase extends LoggingTestCase {
-
- private final Map<StreamShape, Set<? extends BaseStreamTestScenario>> testScenarios;
-
- protected OpTestCase() {
- testScenarios = new EnumMap<>(StreamShape.class);
- testScenarios.put(StreamShape.REFERENCE, Collections.unmodifiableSet(EnumSet.allOf(StreamTestScenario.class)));
- testScenarios.put(StreamShape.INT_VALUE, Collections.unmodifiableSet(EnumSet.allOf(IntStreamTestScenario.class)));
- testScenarios.put(StreamShape.LONG_VALUE, Collections.unmodifiableSet(EnumSet.allOf(LongStreamTestScenario.class)));
- testScenarios.put(StreamShape.DOUBLE_VALUE, Collections.unmodifiableSet(EnumSet.allOf(DoubleStreamTestScenario.class)));
- }
-
- @SuppressWarnings("rawtypes")
- public static int getStreamFlags(BaseStream s) {
- return ((AbstractPipeline) s).getStreamFlags();
- }
-
- /**
- * An asserter for results produced when exercising of stream or terminal
- * tests.
- *
- * @param <R> the type of result to assert on
- */
- public interface ResultAsserter<R> {
- /**
- * Assert a result produced when exercising of stream or terminal
- * test.
- *
- * @param actual the actual result
- * @param expected the expected result
- * @param isOrdered true if the pipeline is ordered
- * @param isParallel true if the pipeline is parallel
- */
- void assertResult(R actual, R expected, boolean isOrdered, boolean isParallel);
- }
-
- // Exercise stream operations
-
- public interface BaseStreamTestScenario {
- StreamShape getShape();
-
- boolean isParallel();
-
- boolean isOrdered();
-
- default <T, S_IN extends BaseStream<T, S_IN>>
- S_IN getStream(TestData<T, S_IN> data) {
- return isParallel()
- ? data.parallelStream()
- : data.stream();
- }
-
- <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
- void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m);
- }
-
- protected <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
- Collection<U> exerciseOps(TestData<T, S_IN> data, Function<S_IN, S_OUT> m) {
- return withData(data).stream(m).exercise();
- }
-
- // Run multiple versions of exercise(), returning the result of the first, and asserting that others return the same result
- // If the first version is s -> s.foo(), can be used with s -> s.mapToInt(i -> i).foo().mapToObj(i -> i) to test all shape variants
- @SafeVarargs
- protected final<T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
- Collection<U> exerciseOpsMulti(TestData<T, S_IN> data,
- Function<S_IN, S_OUT>... ms) {
- Collection<U> result = null;
- for (Function<S_IN, S_OUT> m : ms) {
- if (result == null)
- result = withData(data).stream(m).exercise();
- else {
- Collection<U> r2 = withData(data).stream(m).exercise();
- assertEquals(result, r2);
- }
- }
- return result;
- }
-
- // Run multiple versions of exercise() for an Integer stream, returning the result of the first, and asserting that others return the same result
- // Automates the conversion between Stream<Integer> and {Int,Long,Double}Stream and back, so client sites look like you are passing the same
- // lambda four times, but in fact they are four different lambdas since they are transforming four different kinds of streams
- protected final
- Collection<Integer> exerciseOpsInt(TestData.OfRef<Integer> data,
- Function<Stream<Integer>, Stream<Integer>> mRef,
- Function<IntStream, IntStream> mInt,
- Function<LongStream, LongStream> mLong,
- Function<DoubleStream, DoubleStream> mDouble) {
- @SuppressWarnings({ "rawtypes", "unchecked" })
- Function<Stream<Integer>, Stream<Integer>>[] ms = new Function[4];
- ms[0] = mRef;
- ms[1] = s -> mInt.apply(s.mapToInt(e -> e)).mapToObj(e -> e);
- ms[2] = s -> mLong.apply(s.mapToLong(e -> e)).mapToObj(e -> (int) e);
- ms[3] = s -> mDouble.apply(s.mapToDouble(e -> e)).mapToObj(e -> (int) e);
- return exerciseOpsMulti(data, ms);
- }
-
- // Run multiple versions of exercise() with multiple terminal operations for all kinds of stream, , and asserting against the expected result
- // If the first version is s -> s.foo(), can be used with s -> s.mapToInt(i -> i).foo().mapToObj(i -> i) to test all shape variants
- protected final<T, U, R, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
- void exerciseTerminalOpsMulti(TestData<T, S_IN> data,
- R expected,
- Map<String, Function<S_IN, S_OUT>> streams,
- Map<String, Function<S_OUT, R>> terminals) {
- for (Map.Entry<String, Function<S_IN, S_OUT>> se : streams.entrySet()) {
- setContext("Intermediate stream", se.getKey());
- for (Map.Entry<String, Function<S_OUT, R>> te : terminals.entrySet()) {
- setContext("Terminal stream", te.getKey());
- withData(data)
- .terminal(se.getValue(), te.getValue())
- .expectedResult(expected)
- .exercise();
-
- }
- }
- }
-
- // Run multiple versions of exercise() with multiple terminal operation for all kinds of stream, and asserting against the expected result
- // Automates the conversion between Stream<Integer> and {Int,Long,Double}Stream and back, so client sites look like you are passing the same
- // lambda four times, but in fact they are four different lambdas since they are transforming four different kinds of streams
- protected final
- void exerciseTerminalOpsInt(TestData<Integer, Stream<Integer>> data,
- Collection<Integer> expected,
- String desc,
- Function<Stream<Integer>, Stream<Integer>> mRef,
- Function<IntStream, IntStream> mInt,
- Function<LongStream, LongStream> mLong,
- Function<DoubleStream, DoubleStream> mDouble,
- Map<String, Function<Stream<Integer>, Collection<Integer>>> terminals) {
-
- Map<String, Function<Stream<Integer>, Stream<Integer>>> m = new HashMap<>();
- m.put("Ref " + desc, mRef);
- m.put("Int " + desc, s -> mInt.apply(s.mapToInt(e -> e)).mapToObj(e -> e));
- m.put("Long " + desc, s -> mLong.apply(s.mapToLong(e -> e)).mapToObj(e -> (int) e));
- m.put("Double " + desc, s -> mDouble.apply(s.mapToDouble(e -> e)).mapToObj(e -> (int) e));
-
- exerciseTerminalOpsMulti(data, expected, m, terminals);
- }
-
-
- protected <T, U, S_OUT extends BaseStream<U, S_OUT>>
- Collection<U> exerciseOps(Collection<T> data, Function<Stream<T>, S_OUT> m) {
- TestData.OfRef<T> data1 = TestData.Factory.ofCollection("Collection of type " + data.getClass().getName(), data);
- return withData(data1).stream(m).exercise();
- }
-
- protected <T, U, S_OUT extends BaseStream<U, S_OUT>, I extends Iterable<U>>
- Collection<U> exerciseOps(Collection<T> data, Function<Stream<T>, S_OUT> m, I expected) {
- TestData.OfRef<T> data1 = TestData.Factory.ofCollection("Collection of type " + data.getClass().getName(), data);
- return withData(data1).stream(m).expectedResult(expected).exercise();
- }
-
- @SuppressWarnings("unchecked")
- protected <U, S_OUT extends BaseStream<U, S_OUT>>
- Collection<U> exerciseOps(int[] data, Function<IntStream, S_OUT> m) {
- return withData(TestData.Factory.ofArray("int array", data)).stream(m).exercise();
- }
-
- protected Collection<Integer> exerciseOps(int[] data, Function<IntStream, IntStream> m, int[] expected) {
- TestData.OfInt data1 = TestData.Factory.ofArray("int array", data);
- return withData(data1).stream(m).expectedResult(expected).exercise();
- }
-
- protected <T, S_IN extends BaseStream<T, S_IN>> DataStreamBuilder<T, S_IN> withData(TestData<T, S_IN> data) {
- Objects.requireNonNull(data);
- return new DataStreamBuilder<>(data);
- }
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- public class DataStreamBuilder<T, S_IN extends BaseStream<T, S_IN>> {
- final TestData<T, S_IN> data;
-
- private DataStreamBuilder(TestData<T, S_IN> data) {
- this.data = Objects.requireNonNull(data);
- }
-
- public <U, S_OUT extends BaseStream<U, S_OUT>>
- ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> ops(IntermediateTestOp... ops) {
- return new ExerciseDataStreamBuilder<>(data, (S_IN s) -> (S_OUT) chain(s, ops));
- }
-
- public <U, S_OUT extends BaseStream<U, S_OUT>> ExerciseDataStreamBuilder<T, U, S_IN, S_OUT>
- stream(Function<S_IN, S_OUT> m) {
- return new ExerciseDataStreamBuilder<>(data, m);
- }
-
- public <U, S_OUT extends BaseStream<U, S_OUT>> ExerciseDataStreamBuilder<T, U, S_IN, S_OUT>
- stream(Function<S_IN, S_OUT> m, IntermediateTestOp<U, U> additionalOp) {
- return new ExerciseDataStreamBuilder<>(data, s -> (S_OUT) chain(m.apply(s), additionalOp));
- }
-
- public <R> ExerciseDataTerminalBuilder<T, T, R, S_IN, S_IN>
- terminal(Function<S_IN, R> terminalF) {
- return new ExerciseDataTerminalBuilder<>(data, s -> s, terminalF);
- }
-
- public <U, R, S_OUT extends BaseStream<U, S_OUT>> ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT>
- terminal(Function<S_IN, S_OUT> streamF, Function<S_OUT, R> terminalF) {
- return new ExerciseDataTerminalBuilder<>(data, streamF, terminalF);
- }
- }
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- public class ExerciseDataStreamBuilder<T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>> {
- final TestData<T, S_IN> data;
- final Function<S_IN, S_OUT> m;
- final StreamShape shape;
-
- Set<BaseStreamTestScenario> testSet = new HashSet<>();
-
- Collection<U> refResult;
-
- Consumer<TestData<T, S_IN>> before = LambdaTestHelpers.bEmpty;
-
- Consumer<TestData<T, S_IN>> after = LambdaTestHelpers.bEmpty;
-
- ResultAsserter<Iterable<U>> resultAsserter = (act, exp, ord, par) -> {
- if (par & !ord) {
- LambdaTestHelpers.assertContentsUnordered(act, exp);
- }
- else {
- LambdaTestHelpers.assertContentsEqual(act, exp);
- }
- };
-
- private ExerciseDataStreamBuilder(TestData<T, S_IN> data, Function<S_IN, S_OUT> m) {
- this.data = data;
-
- this.m = Objects.requireNonNull(m);
-
- this.shape = ((AbstractPipeline<?, U, ?>) m.apply(data.stream())).getOutputShape();
-
- // Have to initiate from the output shape of the last stream
- // This means the stream mapper is required first rather than last
- testSet.addAll(testScenarios.get(shape));
- }
-
- //
-
- public <I extends Iterable<U>> ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(I expectedResult) {
- List<U> l = new ArrayList<>();
- expectedResult.forEach(l::add);
- refResult = l;
- return this;
- }
-
- public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(int[] expectedResult) {
- List l = new ArrayList();
- for (int anExpectedResult : expectedResult) {
- l.add(anExpectedResult);
- }
- refResult = l;
- return this;
- }
-
- public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(long[] expectedResult) {
- List l = new ArrayList();
- for (long anExpectedResult : expectedResult) {
- l.add(anExpectedResult);
- }
- refResult = l;
- return this;
- }
-
- public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(double[] expectedResult) {
- List l = new ArrayList();
- for (double anExpectedResult : expectedResult) {
- l.add(anExpectedResult);
- }
- refResult = l;
- return this;
- }
-
- public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> before(Consumer<TestData<T, S_IN>> before) {
- this.before = Objects.requireNonNull(before);
- return this;
- }
-
- public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> after(Consumer<TestData<T, S_IN>> after) {
- this.after = Objects.requireNonNull(after);
- return this;
- }
-
- public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> without(BaseStreamTestScenario... tests) {
- return without(Arrays.asList(tests));
- }
-
- public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> without(Collection<? extends BaseStreamTestScenario> tests) {
- for (BaseStreamTestScenario ts : tests) {
- if (ts.getShape() == shape) {
- testSet.remove(ts);
- }
- }
-
- if (testSet.isEmpty()) {
- throw new IllegalStateException("Test scenario set is empty");
- }
-
- return this;
- }
-
- public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> with(BaseStreamTestScenario... tests) {
- return with(Arrays.asList(tests));
- }
-
- public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> with(Collection<? extends BaseStreamTestScenario> tests) {
- testSet = new HashSet<>();
-
- for (BaseStreamTestScenario ts : tests) {
- if (ts.getShape() == shape) {
- testSet.add(ts);
- }
- }
-
- if (testSet.isEmpty()) {
- throw new IllegalStateException("Test scenario set is empty");
- }
-
- return this;
- }
-
- public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> resultAsserter(ResultAsserter<Iterable<U>> resultAsserter) {
- this.resultAsserter = resultAsserter;
- return this;
- }
-
- // Build method
-
- public Collection<U> exercise() {
- final boolean isStreamOrdered;
- if (refResult == null) {
- // Induce the reference result
- before.accept(data);
- try (S_OUT sOut = m.apply(data.stream())) {
- isStreamOrdered = StreamOpFlag.ORDERED.isKnown(((AbstractPipeline) sOut).getStreamFlags());
- Node<U> refNodeResult = ((AbstractPipeline<?, U, ?>) sOut).evaluateToArrayNode(size -> (U[]) new Object[size]);
- refResult = LambdaTestHelpers.toBoxedList(refNodeResult.spliterator());
- }
- after.accept(data);
- }
- else {
- try (S_OUT sOut = m.apply(data.stream())) {
- isStreamOrdered = StreamOpFlag.ORDERED.isKnown(((AbstractPipeline) sOut).getStreamFlags());
- }
- }
-
- List<Error> errors = new ArrayList<>();
- for (BaseStreamTestScenario test : testSet) {
- try {
- before.accept(data);
-
- List<U> result = new ArrayList<>();
- test.run(data, LambdaTestHelpers.<U>toBoxingConsumer(result::add), m);
-
- Runnable asserter = () -> resultAsserter.assertResult(result, refResult, isStreamOrdered && test.isOrdered(), test.isParallel());
-
- if (refResult.size() > 1000) {
- LambdaTestHelpers.launderAssertion(
- asserter,
- () -> String.format("%n%s: [actual size=%d] != [expected size=%d]", test, result.size(), refResult.size()));
- }
- else {
- LambdaTestHelpers.launderAssertion(
- asserter,
- () -> String.format("%n%s: [actual] %s != [expected] %s", test, result, refResult));
- }
-
- after.accept(data);
- } catch (Throwable t) {
- errors.add(new Error(String.format("%s: %s", test, t), t));
- }
- }
-
- if (!errors.isEmpty()) {
- StringBuilder sb = new StringBuilder();
- int i = 1;
- for (Error t : errors) {
- sb.append(i++).append(": ");
- if (t instanceof AssertionError) {
- sb.append(t).append("\n");
- }
- else {
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
-
- t.getCause().printStackTrace(pw);
- pw.flush();
- sb.append(t).append("\n").append(sw);
- }
- }
- sb.append("--");
-
- fail(String.format("%d failure(s) for test data: %s\n%s", i - 1, data.toString(), sb));
- }
-
- return refResult;
- }
- }
-
- // Exercise terminal operations
-
- interface BaseTerminalTestScenario<U, R, S_OUT extends BaseStream<U, S_OUT>> {
- boolean requiresSingleStageSource();
-
- boolean requiresParallelSource();
-
- default R run(Function<S_OUT, R> terminalF, S_OUT source, StreamShape shape) {
- return terminalF.apply(source);
- }
- }
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- enum TerminalTestScenario implements BaseTerminalTestScenario {
- SINGLE_SEQUENTIAL(true, false),
-
- SINGLE_SEQUENTIAL_SHORT_CIRCUIT(true, false) {
- @Override
- public Object run(Function terminalF, BaseStream source, StreamShape shape) {
- source = (BaseStream) chain(source, new ShortCircuitOp(shape));
- return terminalF.apply(source);
- }
- },
-
- SINGLE_PARALLEL(true, true),
-
- ALL_SEQUENTIAL(false, false),
-
- ALL_SEQUENTIAL_SHORT_CIRCUIT(false, false) {
- @Override
- public Object run(Function terminalF, BaseStream source, StreamShape shape) {
- source = (BaseStream) chain(source, new ShortCircuitOp(shape));
- return terminalF.apply(source);
- }
- },
-
- ALL_PARALLEL(false, true),
-
- ALL_PARALLEL_SEQUENTIAL(false, false) {
- @Override
- public Object run(Function terminalF, BaseStream source, StreamShape shape) {
- return terminalF.apply(source.sequential());
- }
- },
- ;
-
- private final boolean requiresSingleStageSource;
- private final boolean isParallel;
-
- TerminalTestScenario(boolean requiresSingleStageSource, boolean isParallel) {
- this.requiresSingleStageSource = requiresSingleStageSource;
- this.isParallel = isParallel;
- }
-
- @Override
- public boolean requiresSingleStageSource() {
- return requiresSingleStageSource;
- }
-
- @Override
- public boolean requiresParallelSource() {
- return isParallel;
- }
-
- }
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- public class ExerciseDataTerminalBuilder<T, U, R, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>> {
- final TestData<T, S_IN> data;
- final Function<S_IN, S_OUT> streamF;
- final Function<S_OUT, R> terminalF;
-
- R refResult;
-
- ResultAsserter<R> resultAsserter = (act, exp, ord, par) -> LambdaTestHelpers.assertContentsEqual(act, exp);
-
- private ExerciseDataTerminalBuilder(TestData<T, S_IN> data, Function<S_IN, S_OUT> streamF, Function<S_OUT, R> terminalF) {
- this.data = data;
- this.streamF = Objects.requireNonNull(streamF);
- this.terminalF = Objects.requireNonNull(terminalF);
- }
-
- //
-
- public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> expectedResult(R expectedResult) {
- this.refResult = expectedResult;
- return this;
- }
-
- public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> equalator(BiConsumer<R, R> equalityAsserter) {
- resultAsserter = (act, exp, ord, par) -> equalityAsserter.accept(act, exp);
- return this;
- }
-
- public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> resultAsserter(ResultAsserter<R> resultAsserter) {
- this.resultAsserter = resultAsserter;
- return this;
- }
-
- // Build method
-
- public R exercise() {
- boolean isOrdered;
- StreamShape shape;
- Node<U> node;
- try (S_OUT out = streamF.apply(data.stream()).sequential()) {
- AbstractPipeline ap = (AbstractPipeline) out;
- isOrdered = StreamOpFlag.ORDERED.isKnown(ap.getStreamFlags());
- shape = ap.getOutputShape();
- // Sequentially collect the output that will be input to the terminal op
- node = ap.evaluateToArrayNode(size -> (U[]) new Object[size]);
- }
-
- EnumSet<TerminalTestScenario> tests = EnumSet.allOf(TerminalTestScenario.class);
- if (refResult == null) {
- // Induce the reference result
- S_OUT source = (S_OUT) createPipeline(shape, node.spliterator(),
- StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED,
- false);
-
- refResult = (R) TerminalTestScenario.SINGLE_SEQUENTIAL.run(terminalF, source, shape);
- tests.remove(TerminalTestScenario.SINGLE_SEQUENTIAL);
- }
-
- for (BaseTerminalTestScenario test : tests) {
- S_OUT source;
- if (test.requiresSingleStageSource()) {
- source = (S_OUT) createPipeline(shape, node.spliterator(),
- StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED,
- test.requiresParallelSource());
- }
- else {
- source = streamF.apply(test.requiresParallelSource()
- ? data.parallelStream() : data.stream());
- }
-
- R result;
- try (source) {
- result = (R) test.run(terminalF, source, shape);
- }
- LambdaTestHelpers.launderAssertion(
- () -> resultAsserter.assertResult(result, refResult, isOrdered, test.requiresParallelSource()),
- () -> String.format("%s: %s != %s", test, refResult, result));
- }
-
- return refResult;
- }
-
- AbstractPipeline createPipeline(StreamShape shape, Spliterator s, int flags, boolean parallel) {
- switch (shape) {
- case REFERENCE: return new ReferencePipeline.Head<>(s, flags, parallel);
- case INT_VALUE: return new IntPipeline.Head(s, flags, parallel);
- case LONG_VALUE: return new LongPipeline.Head(s, flags, parallel);
- case DOUBLE_VALUE: return new DoublePipeline.Head(s, flags, parallel);
- default: throw new IllegalStateException("Unknown shape: " + shape);
- }
- }
- }
-
- protected <T, R> R exerciseTerminalOps(Collection<T> data, Function<Stream<T>, R> m, R expected) {
- TestData.OfRef<T> data1
- = TestData.Factory.ofCollection("Collection of type " + data.getClass().getName(), data);
- return withData(data1).terminal(m).expectedResult(expected).exercise();
- }
-
- protected <T, R, S_IN extends BaseStream<T, S_IN>> R
- exerciseTerminalOps(TestData<T, S_IN> data,
- Function<S_IN, R> terminalF) {
- return withData(data).terminal(terminalF).exercise();
- }
-
- protected <T, U, R, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>> R
- exerciseTerminalOps(TestData<T, S_IN> data,
- Function<S_IN, S_OUT> streamF,
- Function<S_OUT, R> terminalF) {
- return withData(data).terminal(streamF, terminalF).exercise();
- }
-
- //
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- private static <T> AbstractPipeline<?, T, ?> chain(AbstractPipeline upstream, IntermediateTestOp<?, T> op) {
- return (AbstractPipeline<?, T, ?>) IntermediateTestOp.chain(upstream, op);
- }
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- private static AbstractPipeline<?, ?, ?> chain(AbstractPipeline pipe, IntermediateTestOp... ops) {
- for (IntermediateTestOp op : ops)
- pipe = chain(pipe, op);
- return pipe;
- }
-
- @SuppressWarnings("rawtypes")
- private static <T> AbstractPipeline<?, T, ?> chain(BaseStream pipe, IntermediateTestOp<?, T> op) {
- return chain((AbstractPipeline) pipe, op);
- }
-
- @SuppressWarnings("rawtypes")
- public static AbstractPipeline<?, ?, ?> chain(BaseStream pipe, IntermediateTestOp... ops) {
- return chain((AbstractPipeline) pipe, ops);
- }
-
- // Test data
-
- static class ShortCircuitOp<T> implements StatelessTestOp<T,T> {
- private final StreamShape shape;
-
- ShortCircuitOp(StreamShape shape) {
- this.shape = shape;
- }
-
- @Override
- public Sink<T> opWrapSink(int flags, boolean parallel, Sink<T> sink) {
- return sink;
- }
-
- @Override
- public int opGetFlags() {
- return StreamOpFlag.IS_SHORT_CIRCUIT;
- }
-
- @Override
- public StreamShape outputShape() {
- return shape;
- }
-
- @Override
- public StreamShape inputShape() {
- return shape;
- }
- }
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/SpliteratorTestHelper.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,715 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import org.testng.annotations.Test;
-
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Spliterator;
-import java.util.function.*;
-
-import static org.testng.Assert.*;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.fail;
-
-/**
- * Assertion methods for spliterators, to be called from other tests
- */
-public class SpliteratorTestHelper {
-
- public interface ContentAsserter<T> {
- void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered);
- }
-
- private static ContentAsserter<Object> DEFAULT_CONTENT_ASSERTER
- = SpliteratorTestHelper::assertContents;
-
- @SuppressWarnings("unchecked")
- private static <T> ContentAsserter<T> defaultContentAsserter() {
- return (ContentAsserter<T>) DEFAULT_CONTENT_ASSERTER;
- }
-
- public static void testSpliterator(Supplier<Spliterator<Integer>> supplier) {
- testSpliterator(supplier, defaultContentAsserter());
- }
-
- public static void testSpliterator(Supplier<Spliterator<Integer>> supplier,
- ContentAsserter<Integer> asserter) {
- testSpliterator(supplier, (Consumer<Integer> b) -> b, asserter);
- }
-
- public static void testIntSpliterator(Supplier<Spliterator.OfInt> supplier) {
- testIntSpliterator(supplier, defaultContentAsserter());
- }
-
- public static void testIntSpliterator(Supplier<Spliterator.OfInt> supplier,
- ContentAsserter<Integer> asserter) {
- class BoxingAdapter implements Consumer<Integer>, IntConsumer {
- private final Consumer<Integer> b;
-
- BoxingAdapter(Consumer<Integer> b) {
- this.b = b;
- }
-
- @Override
- public void accept(Integer value) {
- throw new IllegalStateException();
- }
-
- @Override
- public void accept(int value) {
- b.accept(value);
- }
- }
-
- testSpliterator(supplier, BoxingAdapter::new, asserter);
- }
-
- public static void testLongSpliterator(Supplier<Spliterator.OfLong> supplier) {
- testLongSpliterator(supplier, defaultContentAsserter());
- }
-
- public static void testLongSpliterator(Supplier<Spliterator.OfLong> supplier,
- ContentAsserter<Long> asserter) {
- class BoxingAdapter implements Consumer<Long>, LongConsumer {
- private final Consumer<Long> b;
-
- BoxingAdapter(Consumer<Long> b) {
- this.b = b;
- }
-
- @Override
- public void accept(Long value) {
- throw new IllegalStateException();
- }
-
- @Override
- public void accept(long value) {
- b.accept(value);
- }
- }
-
- testSpliterator(supplier, BoxingAdapter::new, asserter);
- }
-
- public static void testDoubleSpliterator(Supplier<Spliterator.OfDouble> supplier) {
- testDoubleSpliterator(supplier, defaultContentAsserter());
- }
-
- public static void testDoubleSpliterator(Supplier<Spliterator.OfDouble> supplier,
- ContentAsserter<Double> asserter) {
- class BoxingAdapter implements Consumer<Double>, DoubleConsumer {
- private final Consumer<Double> b;
-
- BoxingAdapter(Consumer<Double> b) {
- this.b = b;
- }
-
- @Override
- public void accept(Double value) {
- throw new IllegalStateException();
- }
-
- @Override
- public void accept(double value) {
- b.accept(value);
- }
- }
-
- testSpliterator(supplier, BoxingAdapter::new, asserter);
- }
-
- static <T, S extends Spliterator<T>> void testSpliterator(Supplier<S> supplier,
- UnaryOperator<Consumer<T>> boxingAdapter,
- ContentAsserter<T> asserter) {
- ArrayList<T> fromForEach = new ArrayList<>();
- Spliterator<T> spliterator = supplier.get();
- Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add);
- spliterator.forEachRemaining(addToFromForEach);
-
- Collection<T> exp = Collections.unmodifiableList(fromForEach);
-
- testNullPointerException(supplier);
- testForEach(exp, supplier, boxingAdapter, asserter);
- testTryAdvance(exp, supplier, boxingAdapter, asserter);
- testMixedTryAdvanceForEach(exp, supplier, boxingAdapter, asserter);
- testMixedTraverseAndSplit(exp, supplier, boxingAdapter, asserter);
- testSplitAfterFullTraversal(supplier, boxingAdapter);
- testSplitOnce(exp, supplier, boxingAdapter, asserter);
- testSplitSixDeep(exp, supplier, boxingAdapter, asserter);
- testSplitUntilNull(exp, supplier, boxingAdapter, asserter);
- }
-
- //
-
- private static <T, S extends Spliterator<T>> void testNullPointerException(Supplier<S> s) {
- S sp = s.get();
- // Have to check instances and use casts to avoid tripwire messages and
- // directly test the primitive methods
- if (sp instanceof Spliterator.OfInt) {
- Spliterator.OfInt psp = (Spliterator.OfInt) sp;
- executeAndCatch(NullPointerException.class, () -> psp.forEachRemaining((IntConsumer) null));
- executeAndCatch(NullPointerException.class, () -> psp.tryAdvance((IntConsumer) null));
- }
- else if (sp instanceof Spliterator.OfLong) {
- Spliterator.OfLong psp = (Spliterator.OfLong) sp;
- executeAndCatch(NullPointerException.class, () -> psp.forEachRemaining((LongConsumer) null));
- executeAndCatch(NullPointerException.class, () -> psp.tryAdvance((LongConsumer) null));
- }
- else if (sp instanceof Spliterator.OfDouble) {
- Spliterator.OfDouble psp = (Spliterator.OfDouble) sp;
- executeAndCatch(NullPointerException.class, () -> psp.forEachRemaining((DoubleConsumer) null));
- executeAndCatch(NullPointerException.class, () -> psp.tryAdvance((DoubleConsumer) null));
- }
- else {
- executeAndCatch(NullPointerException.class, () -> sp.forEachRemaining(null));
- executeAndCatch(NullPointerException.class, () -> sp.tryAdvance(null));
- }
- }
-
- private static <T, S extends Spliterator<T>> void testForEach(
- Collection<T> exp,
- Supplier<S> supplier,
- UnaryOperator<Consumer<T>> boxingAdapter,
- ContentAsserter<T> asserter) {
- S spliterator = supplier.get();
- long sizeIfKnown = spliterator.getExactSizeIfKnown();
- boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
-
- ArrayList<T> fromForEach = new ArrayList<>();
- spliterator = supplier.get();
- Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add);
- spliterator.forEachRemaining(addToFromForEach);
-
- // Assert that forEach now produces no elements
- spliterator.forEachRemaining(boxingAdapter.apply(
- e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
- // Assert that tryAdvance now produce no elements
- spliterator.tryAdvance(boxingAdapter.apply(
- e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
-
- // assert that size, tryAdvance, and forEach are consistent
- if (sizeIfKnown >= 0) {
- assertEquals(sizeIfKnown, exp.size());
- }
- assertEquals(fromForEach.size(), exp.size());
-
- asserter.assertContents(fromForEach, exp, isOrdered);
- }
-
- private static <T, S extends Spliterator<T>> void testTryAdvance(
- Collection<T> exp,
- Supplier<S> supplier,
- UnaryOperator<Consumer<T>> boxingAdapter,
- ContentAsserter<T> asserter) {
- S spliterator = supplier.get();
- long sizeIfKnown = spliterator.getExactSizeIfKnown();
- boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
-
- spliterator = supplier.get();
- ArrayList<T> fromTryAdvance = new ArrayList<>();
- Consumer<T> addToFromTryAdvance = boxingAdapter.apply(fromTryAdvance::add);
- while (spliterator.tryAdvance(addToFromTryAdvance)) { }
-
- // Assert that forEach now produces no elements
- spliterator.forEachRemaining(boxingAdapter.apply(
- e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
- // Assert that tryAdvance now produce no elements
- spliterator.tryAdvance(boxingAdapter.apply(
- e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
-
- // assert that size, tryAdvance, and forEach are consistent
- if (sizeIfKnown >= 0) {
- assertEquals(sizeIfKnown, exp.size());
- }
- assertEquals(fromTryAdvance.size(), exp.size());
-
- asserter.assertContents(fromTryAdvance, exp, isOrdered);
- }
-
- private static <T, S extends Spliterator<T>> void testMixedTryAdvanceForEach(
- Collection<T> exp,
- Supplier<S> supplier,
- UnaryOperator<Consumer<T>> boxingAdapter,
- ContentAsserter<T> asserter) {
- S spliterator = supplier.get();
- long sizeIfKnown = spliterator.getExactSizeIfKnown();
- boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
-
- // tryAdvance first few elements, then forEach rest
- ArrayList<T> dest = new ArrayList<>();
- spliterator = supplier.get();
- Consumer<T> addToDest = boxingAdapter.apply(dest::add);
- for (int i = 0; i < 10 && spliterator.tryAdvance(addToDest); i++) { }
- spliterator.forEachRemaining(addToDest);
-
- // Assert that forEach now produces no elements
- spliterator.forEachRemaining(boxingAdapter.apply(
- e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
- // Assert that tryAdvance now produce no elements
- spliterator.tryAdvance(boxingAdapter.apply(
- e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
-
- if (sizeIfKnown >= 0) {
- assertEquals(sizeIfKnown, dest.size());
- }
- assertEquals(dest.size(), exp.size());
-
- asserter.assertContents(dest, exp, isOrdered);
- }
-
- private static <T, S extends Spliterator<T>> void testMixedTraverseAndSplit(
- Collection<T> exp,
- Supplier<S> supplier,
- UnaryOperator<Consumer<T>> boxingAdapter,
- ContentAsserter<T> asserter) {
- S spliterator = supplier.get();
- long sizeIfKnown = spliterator.getExactSizeIfKnown();
- boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
-
- // tryAdvance first few elements, then forEach rest
- ArrayList<T> dest = new ArrayList<>();
- spliterator = supplier.get();
- Consumer<T> b = boxingAdapter.apply(dest::add);
-
- Spliterator<T> spl1, spl2, spl3;
- spliterator.tryAdvance(b);
- spl2 = spliterator.trySplit();
- if (spl2 != null) {
- spl2.tryAdvance(b);
- spl1 = spl2.trySplit();
- if (spl1 != null) {
- spl1.tryAdvance(b);
- spl1.forEachRemaining(b);
- }
- spl2.tryAdvance(b);
- spl2.forEachRemaining(b);
- }
- spliterator.tryAdvance(b);
- spl3 = spliterator.trySplit();
- if (spl3 != null) {
- spl3.tryAdvance(b);
- spl3.forEachRemaining(b);
- }
- spliterator.tryAdvance(b);
- spliterator.forEachRemaining(b);
-
- if (sizeIfKnown >= 0) {
- assertEquals(sizeIfKnown, dest.size());
- }
- assertEquals(dest.size(), exp.size());
-
- asserter.assertContents(dest, exp, isOrdered);
- }
-
- private static <T, S extends Spliterator<T>> void testSplitAfterFullTraversal(
- Supplier<S> supplier,
- UnaryOperator<Consumer<T>> boxingAdapter) {
- // Full traversal using tryAdvance
- Spliterator<T> spliterator = supplier.get();
- while (spliterator.tryAdvance(boxingAdapter.apply(e -> { }))) { }
- Spliterator<T> split = spliterator.trySplit();
- assertNull(split);
-
- // Full traversal using forEach
- spliterator = supplier.get();
- spliterator.forEachRemaining(boxingAdapter.apply(e -> { }));
- split = spliterator.trySplit();
- assertNull(split);
-
- // Full traversal using tryAdvance then forEach
- spliterator = supplier.get();
- spliterator.tryAdvance(boxingAdapter.apply(e -> { }));
- spliterator.forEachRemaining(boxingAdapter.apply(e -> { }));
- split = spliterator.trySplit();
- assertNull(split);
- }
-
- private static <T, S extends Spliterator<T>> void testSplitOnce(
- Collection<T> exp,
- Supplier<S> supplier,
- UnaryOperator<Consumer<T>> boxingAdapter,
- ContentAsserter<T> asserter) {
- S spliterator = supplier.get();
- long sizeIfKnown = spliterator.getExactSizeIfKnown();
- boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
-
- ArrayList<T> fromSplit = new ArrayList<>();
- Spliterator<T> s1 = supplier.get();
- Spliterator<T> s2 = s1.trySplit();
- long s1Size = s1.getExactSizeIfKnown();
- long s2Size = (s2 != null) ? s2.getExactSizeIfKnown() : 0;
- Consumer<T> addToFromSplit = boxingAdapter.apply(fromSplit::add);
- if (s2 != null)
- s2.forEachRemaining(addToFromSplit);
- s1.forEachRemaining(addToFromSplit);
-
- if (sizeIfKnown >= 0) {
- assertEquals(sizeIfKnown, fromSplit.size());
- if (s1Size >= 0 && s2Size >= 0)
- assertEquals(sizeIfKnown, s1Size + s2Size);
- }
-
- asserter.assertContents(fromSplit, exp, isOrdered);
- }
-
- private static <T, S extends Spliterator<T>> void testSplitSixDeep(
- Collection<T> exp,
- Supplier<S> supplier,
- UnaryOperator<Consumer<T>> boxingAdapter,
- ContentAsserter<T> asserter) {
- S spliterator = supplier.get();
- boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
-
- for (int depth=0; depth < 6; depth++) {
- List<T> dest = new ArrayList<>();
- spliterator = supplier.get();
-
- assertSpliterator(spliterator);
-
- // verify splitting with forEach
- splitSixDeepVisitor(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), false);
- asserter.assertContents(dest, exp, isOrdered);
-
- // verify splitting with tryAdvance
- dest.clear();
- spliterator = supplier.get();
- splitSixDeepVisitor(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), true);
- asserter.assertContents(dest, exp, isOrdered);
- }
- }
-
- private static <T, S extends Spliterator<T>>
- void splitSixDeepVisitor(int depth, int curLevel,
- List<T> dest, S spliterator, UnaryOperator<Consumer<T>> boxingAdapter,
- int rootCharacteristics, boolean useTryAdvance) {
- if (curLevel < depth) {
- long beforeSize = spliterator.getExactSizeIfKnown();
- Spliterator<T> split = spliterator.trySplit();
- if (split != null) {
- assertSpliterator(split, rootCharacteristics);
- assertSpliterator(spliterator, rootCharacteristics);
-
- if ((rootCharacteristics & Spliterator.SUBSIZED) != 0 &&
- (rootCharacteristics & Spliterator.SIZED) != 0) {
- assertEquals(beforeSize, split.estimateSize() + spliterator.estimateSize());
- }
- splitSixDeepVisitor(depth, curLevel + 1, dest, split, boxingAdapter, rootCharacteristics, useTryAdvance);
- }
- splitSixDeepVisitor(depth, curLevel + 1, dest, spliterator, boxingAdapter, rootCharacteristics, useTryAdvance);
- }
- else {
- long sizeIfKnown = spliterator.getExactSizeIfKnown();
- if (useTryAdvance) {
- Consumer<T> addToDest = boxingAdapter.apply(dest::add);
- int count = 0;
- while (spliterator.tryAdvance(addToDest)) {
- ++count;
- }
-
- if (sizeIfKnown >= 0)
- assertEquals(sizeIfKnown, count);
-
- // Assert that forEach now produces no elements
- spliterator.forEachRemaining(boxingAdapter.apply(
- e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
-
- Spliterator<T> split = spliterator.trySplit();
- assertNull(split);
- }
- else {
- List<T> leafDest = new ArrayList<>();
- Consumer<T> addToLeafDest = boxingAdapter.apply(leafDest::add);
- spliterator.forEachRemaining(addToLeafDest);
-
- if (sizeIfKnown >= 0)
- assertEquals(sizeIfKnown, leafDest.size());
-
- // Assert that forEach now produces no elements
- spliterator.tryAdvance(boxingAdapter.apply(
- e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
-
- Spliterator<T> split = spliterator.trySplit();
- assertNull(split);
-
- dest.addAll(leafDest);
- }
- }
- }
-
- private static <T, S extends Spliterator<T>> void testSplitUntilNull(
- Collection<T> exp,
- Supplier<S> supplier,
- UnaryOperator<Consumer<T>> boxingAdapter,
- ContentAsserter<T> asserter) {
- Spliterator<T> s = supplier.get();
- boolean isOrdered = s.hasCharacteristics(Spliterator.ORDERED);
- assertSpliterator(s);
-
- List<T> splits = new ArrayList<>();
- Consumer<T> c = boxingAdapter.apply(splits::add);
-
- testSplitUntilNull(new SplitNode<T>(c, s));
- asserter.assertContents(splits, exp, isOrdered);
- }
-
- private static class SplitNode<T> {
- // Constant for every node
- final Consumer<T> c;
- final int rootCharacteristics;
-
- final Spliterator<T> s;
-
- SplitNode(Consumer<T> c, Spliterator<T> s) {
- this(c, s.characteristics(), s);
- }
-
- private SplitNode(Consumer<T> c, int rootCharacteristics, Spliterator<T> s) {
- this.c = c;
- this.rootCharacteristics = rootCharacteristics;
- this.s = s;
- }
-
- SplitNode<T> fromSplit(Spliterator<T> split) {
- return new SplitNode<>(c, rootCharacteristics, split);
- }
- }
-
- /**
- * Set the maximum stack capacity to 0.25MB. This should be more than enough to detect a bad spliterator
- * while not unduly disrupting test infrastructure given the test data sizes that are used are small.
- * Note that j.u.c.ForkJoinPool sets the max queue size to 64M (1 << 26).
- */
- private static final int MAXIMUM_STACK_CAPACITY = 1 << 18; // 0.25MB
-
- private static <T> void testSplitUntilNull(SplitNode<T> e) {
- // Use an explicit stack to avoid a StackOverflowException when testing a Spliterator
- // that when repeatedly split produces a right-balanced (and maybe degenerate) tree, or
- // for a spliterator that is badly behaved.
- Deque<SplitNode<T>> stack = new ArrayDeque<>();
- stack.push(e);
-
- int iteration = 0;
- while (!stack.isEmpty()) {
- assertTrue(iteration++ < MAXIMUM_STACK_CAPACITY, "Exceeded maximum stack modification count of 1 << 18");
-
- e = stack.pop();
- Spliterator<T> parentAndRightSplit = e.s;
-
- long parentEstimateSize = parentAndRightSplit.estimateSize();
- assertTrue(parentEstimateSize >= 0,
- String.format("Split size estimate %d < 0", parentEstimateSize));
-
- long parentSize = parentAndRightSplit.getExactSizeIfKnown();
- Spliterator<T> leftSplit = parentAndRightSplit.trySplit();
- if (leftSplit == null) {
- parentAndRightSplit.forEachRemaining(e.c);
- continue;
- }
-
- assertSpliterator(leftSplit, e.rootCharacteristics);
- assertSpliterator(parentAndRightSplit, e.rootCharacteristics);
-
- if (parentEstimateSize != Long.MAX_VALUE && leftSplit.estimateSize() > 0
- && parentAndRightSplit.estimateSize() > 0) {
- assertTrue(leftSplit.estimateSize() < parentEstimateSize,
- String.format("Left split size estimate %d >= parent split size estimate %d",
- leftSplit.estimateSize(), parentEstimateSize));
- assertTrue(parentAndRightSplit.estimateSize() < parentEstimateSize,
- String.format("Right split size estimate %d >= parent split size estimate %d",
- leftSplit.estimateSize(), parentEstimateSize));
- }
- else {
- assertTrue(leftSplit.estimateSize() <= parentEstimateSize,
- String.format("Left split size estimate %d > parent split size estimate %d",
- leftSplit.estimateSize(), parentEstimateSize));
- assertTrue(parentAndRightSplit.estimateSize() <= parentEstimateSize,
- String.format("Right split size estimate %d > parent split size estimate %d",
- leftSplit.estimateSize(), parentEstimateSize));
- }
-
- long leftSize = leftSplit.getExactSizeIfKnown();
- long rightSize = parentAndRightSplit.getExactSizeIfKnown();
- if (parentSize >= 0 && leftSize >= 0 && rightSize >= 0)
- assertEquals(parentSize, leftSize + rightSize,
- String.format("exact left split size %d + exact right split size %d != parent exact split size %d",
- leftSize, rightSize, parentSize));
-
- // Add right side to stack first so left side is popped off first
- stack.push(e.fromSplit(parentAndRightSplit));
- stack.push(e.fromSplit(leftSplit));
- }
- }
-
- private static void assertSpliterator(Spliterator<?> s, int rootCharacteristics) {
- if ((rootCharacteristics & Spliterator.SUBSIZED) != 0) {
- assertTrue(s.hasCharacteristics(Spliterator.SUBSIZED),
- "Child split is not SUBSIZED when root split is SUBSIZED");
- }
- assertSpliterator(s);
- }
-
- private static void assertSpliterator(Spliterator<?> s) {
- if (s.hasCharacteristics(Spliterator.SUBSIZED)) {
- assertTrue(s.hasCharacteristics(Spliterator.SIZED));
- }
- if (s.hasCharacteristics(Spliterator.SIZED)) {
- assertTrue(s.estimateSize() != Long.MAX_VALUE);
- assertTrue(s.getExactSizeIfKnown() >= 0);
- }
- try {
- s.getComparator();
- assertTrue(s.hasCharacteristics(Spliterator.SORTED));
- } catch (IllegalStateException e) {
- assertFalse(s.hasCharacteristics(Spliterator.SORTED));
- }
- }
-
- private static<T> void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered) {
- if (isOrdered) {
- assertEquals(actual, expected);
- }
- else {
- LambdaTestHelpers.assertContentsUnordered(actual, expected);
- }
- }
-
- private static void executeAndCatch(Class<? extends Exception> expected, Runnable r) {
- Exception caught = null;
- try {
- r.run();
- }
- catch (Exception e) {
- caught = e;
- }
-
- assertNotNull(caught,
- String.format("No Exception was thrown, expected an Exception of %s to be thrown",
- expected.getName()));
- assertTrue(expected.isInstance(caught),
- String.format("Exception thrown %s not an instance of %s",
- caught.getClass().getName(), expected.getName()));
- }
-
- static<U> void mixedTraverseAndSplit(Consumer<U> b, Spliterator<U> splTop) {
- Spliterator<U> spl1, spl2, spl3;
- splTop.tryAdvance(b);
- spl2 = splTop.trySplit();
- if (spl2 != null) {
- spl2.tryAdvance(b);
- spl1 = spl2.trySplit();
- if (spl1 != null) {
- spl1.tryAdvance(b);
- spl1.forEachRemaining(b);
- }
- spl2.tryAdvance(b);
- spl2.forEachRemaining(b);
- }
- splTop.tryAdvance(b);
- spl3 = splTop.trySplit();
- if (spl3 != null) {
- spl3.tryAdvance(b);
- spl3.forEachRemaining(b);
- }
- splTop.tryAdvance(b);
- splTop.forEachRemaining(b);
- }
-
- static void mixedTraverseAndSplit(IntConsumer b, Spliterator.OfInt splTop) {
- Spliterator.OfInt spl1, spl2, spl3;
- splTop.tryAdvance(b);
- spl2 = splTop.trySplit();
- if (spl2 != null) {
- spl2.tryAdvance(b);
- spl1 = spl2.trySplit();
- if (spl1 != null) {
- spl1.tryAdvance(b);
- spl1.forEachRemaining(b);
- }
- spl2.tryAdvance(b);
- spl2.forEachRemaining(b);
- }
- splTop.tryAdvance(b);
- spl3 = splTop.trySplit();
- if (spl3 != null) {
- spl3.tryAdvance(b);
- spl3.forEachRemaining(b);
- }
- splTop.tryAdvance(b);
- splTop.forEachRemaining(b);
- }
- static void mixedTraverseAndSplit(LongConsumer b, Spliterator.OfLong splTop) {
- Spliterator.OfLong spl1, spl2, spl3;
- splTop.tryAdvance(b);
- spl2 = splTop.trySplit();
- if (spl2 != null) {
- spl2.tryAdvance(b);
- spl1 = spl2.trySplit();
- if (spl1 != null) {
- spl1.tryAdvance(b);
- spl1.forEachRemaining(b);
- }
- spl2.tryAdvance(b);
- spl2.forEachRemaining(b);
- }
- splTop.tryAdvance(b);
- spl3 = splTop.trySplit();
- if (spl3 != null) {
- spl3.tryAdvance(b);
- spl3.forEachRemaining(b);
- }
- splTop.tryAdvance(b);
- splTop.forEachRemaining(b);
- }
-
- static void mixedTraverseAndSplit(DoubleConsumer b, Spliterator.OfDouble splTop) {
- Spliterator.OfDouble spl1, spl2, spl3;
- splTop.tryAdvance(b);
- spl2 = splTop.trySplit();
- if (spl2 != null) {
- spl2.tryAdvance(b);
- spl1 = spl2.trySplit();
- if (spl1 != null) {
- spl1.tryAdvance(b);
- spl1.forEachRemaining(b);
- }
- spl2.tryAdvance(b);
- spl2.forEachRemaining(b);
- }
- splTop.tryAdvance(b);
- spl3 = splTop.trySplit();
- if (spl3 != null) {
- spl3.tryAdvance(b);
- spl3.forEachRemaining(b);
- }
- splTop.tryAdvance(b);
- splTop.forEachRemaining(b);
- }
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/StatefulTestOp.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,138 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import java.util.Spliterator;
-import java.util.function.IntFunction;
-
-/**
- * The base type for a stateful test operation.
- */
-interface StatefulTestOp<E> extends IntermediateTestOp<E, E> {
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- public static<T> AbstractPipeline chain(AbstractPipeline upstream,
- StatefulTestOp op) {
- switch (op.outputShape()) {
- case REFERENCE:
- return new ReferencePipeline.StatefulOp<Object, T>(upstream, op.inputShape(), op.opGetFlags()) {
- @Override
- Sink opWrapSink(int flags, Sink sink) {
- return op.opWrapSink(flags, isParallel(), sink);
- }
-
- @Override
- <P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper,
- Spliterator<P_IN> spliterator) {
- return op.opEvaluateParallelLazy(helper, spliterator);
- }
-
- @Override
- <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
- Spliterator<P_IN> spliterator,
- IntFunction<T[]> generator) {
- return op.opEvaluateParallel(helper, spliterator, generator);
- }
- };
- case INT_VALUE:
- return new IntPipeline.StatefulOp<Object>(upstream, op.inputShape(), op.opGetFlags()) {
- @Override
- Sink opWrapSink(int flags, Sink sink) {
- return op.opWrapSink(flags, isParallel(), sink);
- }
-
- @Override
- <P_IN> Spliterator<Integer> opEvaluateParallelLazy(PipelineHelper<Integer> helper,
- Spliterator<P_IN> spliterator) {
- return op.opEvaluateParallelLazy(helper, spliterator);
- }
-
- @Override
- <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
- Spliterator<P_IN> spliterator,
- IntFunction<Integer[]> generator) {
- return (Node<Integer>) op.opEvaluateParallel(helper, spliterator, generator);
- }
- };
- case LONG_VALUE:
- return new LongPipeline.StatefulOp<Object>(upstream, op.inputShape(), op.opGetFlags()) {
- @Override
- Sink opWrapSink(int flags, Sink sink) {
- return op.opWrapSink(flags, isParallel(), sink);
- }
-
- @Override
- <P_IN> Spliterator<Long> opEvaluateParallelLazy(PipelineHelper<Long> helper,
- Spliterator<P_IN> spliterator) {
- return op.opEvaluateParallelLazy(helper, spliterator);
- }
-
- @Override
- <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
- Spliterator<P_IN> spliterator,
- IntFunction<Long[]> generator) {
- return (Node<Long>) op.opEvaluateParallel(helper, spliterator, generator);
- }
- };
- case DOUBLE_VALUE:
- return new DoublePipeline.StatefulOp<Object>(upstream, op.inputShape(), op.opGetFlags()) {
- @Override
- Sink opWrapSink(int flags, Sink sink) {
- return op.opWrapSink(flags, isParallel(), sink);
- }
-
- @Override
- <P_IN> Spliterator<Double> opEvaluateParallelLazy(PipelineHelper<Double> helper,
- Spliterator<P_IN> spliterator) {
- return op.opEvaluateParallelLazy(helper, spliterator);
- }
-
- @Override
- <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
- Spliterator<P_IN> spliterator,
- IntFunction<Double[]> generator) {
- return (Node<Double>) op.opEvaluateParallel(helper, spliterator, generator);
- }
- };
- default: throw new IllegalStateException(op.outputShape().toString());
- }
- }
-
- default StreamShape inputShape() { return StreamShape.REFERENCE; }
-
- default StreamShape outputShape() { return StreamShape.REFERENCE; }
-
- default int opGetFlags() { return 0; }
-
- Sink<E> opWrapSink(int flags, boolean parallel, Sink<E> sink);
-
- @SuppressWarnings("unchecked")
- default <P_IN> Spliterator<E> opEvaluateParallelLazy(PipelineHelper<E> helper,
- Spliterator<P_IN> spliterator) {
- return opEvaluateParallel(helper, spliterator, i -> (E[]) new Object[i]).spliterator();
- }
-
- <P_IN> Node<E> opEvaluateParallel(PipelineHelper<E> helper,
- Spliterator<P_IN> spliterator,
- IntFunction<E[]> generator);
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/StatelessTestOp.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-/**
- * The base type of a stateless test operation
- */
-interface StatelessTestOp<E_IN, E_OUT> extends IntermediateTestOp<E_IN, E_OUT> {
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- public static<T> AbstractPipeline chain(AbstractPipeline upstream,
- StatelessTestOp<?, T> op) {
- int flags = op.opGetFlags();
- switch (op.outputShape()) {
- case REFERENCE:
- return new ReferencePipeline.StatelessOp<Object, T>(upstream, op.inputShape(), flags) {
- public Sink opWrapSink(int flags, Sink<T> sink) {
- return op.opWrapSink(flags, isParallel(), sink);
- }
- };
- case INT_VALUE:
- return new IntPipeline.StatelessOp<Object>(upstream, op.inputShape(), flags) {
- public Sink opWrapSink(int flags, Sink sink) {
- return op.opWrapSink(flags, isParallel(), sink);
- }
- };
- case LONG_VALUE:
- return new LongPipeline.StatelessOp<Object>(upstream, op.inputShape(), flags) {
- @Override
- Sink opWrapSink(int flags, Sink sink) {
- return op.opWrapSink(flags, isParallel(), sink);
- }
- };
- case DOUBLE_VALUE:
- return new DoublePipeline.StatelessOp<Object>(upstream, op.inputShape(), flags) {
- @Override
- Sink opWrapSink(int flags, Sink sink) {
- return op.opWrapSink(flags, isParallel(), sink);
- }
- };
- default: throw new IllegalStateException(op.outputShape().toString());
- }
- }
-
- default StreamShape inputShape() { return StreamShape.REFERENCE; }
-
- default StreamShape outputShape() { return StreamShape.REFERENCE; }
-
- default int opGetFlags() { return 0; }
-
- Sink<E_IN> opWrapSink(int flags, boolean parallel, Sink<E_OUT> sink);
-}
-
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/StreamOpFlagTestHelper.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import java.util.EnumSet;
-
-public class StreamOpFlagTestHelper {
-
- /** EnumSet containing stream flags */
- private static final EnumSet<StreamOpFlag> allStreamFlags;
-
- static {
- allStreamFlags = EnumSet.allOf(StreamOpFlag.class);
- for (StreamOpFlag f : EnumSet.allOf(StreamOpFlag.class))
- if (!f.isStreamFlag())
- allStreamFlags.remove(f);
- }
-
-
- static EnumSet<StreamOpFlag> allStreamFlags() {
- // EnumSet is mutable
- return allStreamFlags.clone();
- }
-
- public static boolean isStreamOrdered(Stream<?> s) {
- return StreamOpFlag.ORDERED.isKnown(OpTestCase.getStreamFlags(s));
- }
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/StreamTestDataProvider.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,205 +0,0 @@
-/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import org.testng.annotations.DataProvider;
-
-import java.util.*;
-import java.util.Spliterators;
-import java.util.function.Supplier;
-
-/**
- * StreamTestDataProvider
- *
- * @author Brian Goetz
- */
-/** TestNG DataProvider for ref-valued streams */
-public class StreamTestDataProvider {
- private static final Integer[] to0 = new Integer[0];
- private static final Integer[] to1 = new Integer[1];
- private static final Integer[] to10 = new Integer[10];
- private static final Integer[] to100 = new Integer[100];
- private static final Integer[] to1000 = new Integer[1000];
- private static final Integer[] reversed = new Integer[100];
- private static final Integer[] ones = new Integer[100];
- private static final Integer[] twice = new Integer[200];
- private static final Integer[] pseudoRandom;
-
- private static final Object[][] testData;
- private static final Object[][] withNullTestData;
- private static final Object[][] spliteratorTestData;
-
- static {
- Integer[][] arrays = {to0, to1, to10, to100, to1000};
- for (Integer[] arr : arrays) {
- for (int i = 0; i < arr.length; i++) {
- arr[i] = i;
- }
- }
- for (int i = 0; i < reversed.length; i++) {
- reversed[i] = reversed.length - i;
- }
- for (int i = 0; i < ones.length; i++) {
- ones[i] = 1;
- }
- System.arraycopy(to100, 0, twice, 0, to100.length);
- System.arraycopy(to100, 0, twice, to100.length, to100.length);
- pseudoRandom = new Integer[LambdaTestHelpers.LONG_STRING.length()];
- for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
- pseudoRandom[i] = (int) LambdaTestHelpers.LONG_STRING.charAt(i);
- }
- }
-
- static final Object[][] arrays = {
- {"empty", to0},
- {"0..1", to1},
- {"0..10", to10},
- {"0..100", to100},
- {"0..1000", to1000},
- {"100x[1]", ones},
- {"2x[0..100]", twice},
- {"reverse 0..100", reversed},
- {"pseudorandom", pseudoRandom}
- };
-
- static {
- {
- List<Object[]> list = new ArrayList<>();
- for (Object[] data : arrays) {
- final Object name = data[0];
- final Integer[] ints = (Integer[])data[1];
- final List<Integer> intsAsList = Arrays.asList(ints);
-
- list.add(arrayDataDescr("array:" + name, ints));
- list.add(collectionDataDescr("ArrayList.asList:" + name, intsAsList));
- list.add(collectionDataDescr("ArrayList:" + name, new ArrayList<>(intsAsList)));
- list.add(streamDataDescr("DelegatingStream(ArrayList):" + name,
- () -> new ArrayList<>(intsAsList).stream()));
- List<Integer> aList = new ArrayList<>(intsAsList);
- if (LambdaTestMode.isNormalMode()) {
- // Only include sub-lists for normal test execution mode
- // This data is serialization-hostile since the state of the
- // deserialized sub-list will be out of sync with the
- // enclosing list.
- list.add(collectionDataDescr("ArrayList.Sublist:" + name,
- (ints.length) <= 1 ? aList.subList(0, 0) : aList.subList(1, ints.length / 2)));
- }
- list.add(collectionDataDescr("LinkedList:" + name, new LinkedList<>(intsAsList)));
- list.add(collectionDataDescr("HashSet:" + name, new HashSet<>(intsAsList)));
- list.add(collectionDataDescr("LinkedHashSet:" + name, new LinkedHashSet<>(intsAsList)));
- list.add(collectionDataDescr("TreeSet:" + name, new TreeSet<>(intsAsList)));
- SpinedBuffer<Integer> spinedBuffer = new SpinedBuffer<>();
- intsAsList.forEach(spinedBuffer);
- list.add(sbDataDescr("SpinedBuffer:" + name, spinedBuffer));
-
- // @@@ Add more
- }
- testData = list.toArray(new Object[0][]);
- }
-
- // Simple combination of numbers and null values, probably excessive but may catch
- // errors for initialization/termination/sequence
- // @@@ This is separate from the other data for now until nulls are consistently supported by
- // all operations
- {
- List<Object[]> list = new ArrayList<>();
- int size = 5;
- for (int i = 0; i < (1 << size) - 2; i++) {
- Integer[] content = new Integer[size];
- for (int e = 0; e < size; e++) {
- content[e] = (i & (1 << e)) > 0 ? e + 1 : null;
- }
-
- // ORDERED
- list.add(arrayDataDescr("array:" + i, content));
- // not ORDERED, DISTINCT
- list.add(collectionDataDescr("HashSet:" + i, new HashSet<>(Arrays.asList(content))));
- }
-
- withNullTestData = list.toArray(new Object[0][]);
- }
-
- {
- List<Object[]> spliterators = new ArrayList<>();
- for (Object[] data : arrays) {
- final Object name = data[0];
- final Integer[] ints = (Integer[])data[1];
-
- spliterators.add(splitDescr("Arrays.s(array):" + name,
- () -> Arrays.spliterator(ints)));
- spliterators.add(splitDescr("arrays.s(array,o,l):" + name,
- () -> Arrays.spliterator(ints, 0, ints.length/2)));
- spliterators.add(splitDescr("SpinedBuffer.s():" + name,
- () -> {
- SpinedBuffer<Integer> sb = new SpinedBuffer<>();
- for (Integer i : ints)
- sb.accept(i);
- return sb.spliterator();
- }));
- spliterators.add(splitDescr("Iterators.s(Arrays.s(array).iterator(), size):" + name,
- () -> Spliterators.spliterator(Arrays.asList(ints).iterator(), ints.length, 0)));
- spliterators.add(splitDescr("Iterators.s(Arrays.s(array).iterator()):" + name,
- () -> Spliterators.spliteratorUnknownSize(Arrays.asList(ints).iterator(), 0)));
- // @@@ Add map and collection spliterators when spliterator() is exposed on Collection or Iterable
- }
- spliteratorTestData = spliterators.toArray(new Object[0][]);
- }
- }
-
- static <T> Object[] arrayDataDescr(String description, T[] data) {
- return new Object[] { description, TestData.Factory.ofArray(description, data)};
- }
-
- static <T> Object[] streamDataDescr(String description, Supplier<Stream<T>> supplier) {
- return new Object[] { description, TestData.Factory.ofSupplier(description, supplier)};
- }
-
- static <T> Object[] collectionDataDescr(String description, Collection<T> data) {
- return new Object[] { description, TestData.Factory.ofCollection(description, data)};
- }
-
- static <T> Object[] sbDataDescr(String description, SpinedBuffer<T> data) {
- return new Object[] { description, TestData.Factory.ofSpinedBuffer(description, data)};
- }
-
- static <T> Object[] splitDescr(String description, Supplier<Spliterator<T>> ss) {
- return new Object[] { description, ss };
- }
-
- // Return an array of ( String name, StreamTestData<Integer> )
- @DataProvider(name = "StreamTestData<Integer>")
- public static Object[][] makeStreamTestData() {
- return testData;
- }
-
- @DataProvider(name = "withNull:StreamTestData<Integer>")
- public static Object[][] makeStreamWithNullTestData() {
- return withNullTestData;
- }
-
- // returns an array of (String name, Supplier<Spliterator<Integer>>)
- @DataProvider(name = "Spliterator<Integer>")
- public static Object[][] spliteratorProvider() {
- return spliteratorTestData;
- }
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/StreamTestScenario.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,278 +0,0 @@
-/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.Spliterator;
-import java.util.function.Consumer;
-import java.util.function.Function;
-
-/**
- * Test scenarios for reference streams.
- *
- * Each scenario is provided with a data source, a function that maps a fresh
- * stream (as provided by the data source) to a new stream, and a sink to
- * receive results. Each scenario describes a different way of computing the
- * stream contents. The test driver will ensure that all scenarios produce
- * the same output (modulo allowable differences in ordering).
- */
-@SuppressWarnings({"rawtypes", "unchecked"})
-public enum StreamTestScenario implements OpTestCase.BaseStreamTestScenario {
-
- STREAM_FOR_EACH(false) {
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- Stream<U> s = m.apply(source);
- if (s.isParallel()) {
- s = s.sequential();
- }
- s.forEach(b);
- }
- },
-
- // Collec to list
- STREAM_COLLECT(false) {
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- for (U t : m.apply(source).collect(Collectors.toList())) {
- b.accept(t);
- }
- }
- },
-
- // To array
- STREAM_TO_ARRAY(false) {
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- for (Object t : m.apply(source).toArray()) {
- b.accept((U) t);
- }
- }
- },
-
- // Wrap as stream, and iterate in pull mode
- STREAM_ITERATOR(false) {
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- for (Iterator<U> seqIter = m.apply(source).iterator(); seqIter.hasNext(); )
- b.accept(seqIter.next());
- }
- },
-
- // Wrap as stream, and spliterate then iterate in pull mode
- STREAM_SPLITERATOR(false) {
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- for (Spliterator<U> spl = m.apply(source).spliterator(); spl.tryAdvance(b); ) {
- }
- }
- },
-
- // Wrap as stream, spliterate, then split a few times mixing advances with forEach
- STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(source).spliterator());
- }
- },
-
- // Wrap as stream, and spliterate then iterate in pull mode
- STREAM_SPLITERATOR_FOREACH(false) {
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- m.apply(source).spliterator().forEachRemaining(b);
- }
- },
-
- // Wrap as parallel stream + sequential
- PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- m.apply(source).sequential().forEach(b);
- }
- },
-
- // Wrap as parallel stream + forEachOrdered
- PAR_STREAM_FOR_EACH_ORDERED(true) {
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- // @@@ Want to explicitly select ordered equalator
- m.apply(source).forEachOrdered(b);
- }
- },
-
- // Wrap as stream, and spliterate then iterate sequentially
- PAR_STREAM_SPLITERATOR(true) {
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- for (Spliterator<U> spl = m.apply(source).spliterator(); spl.tryAdvance(b); ) {
- }
- }
- },
-
- // Wrap as stream, and spliterate then iterate sequentially
- PAR_STREAM_SPLITERATOR_FOREACH(true) {
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- m.apply(source).spliterator().forEachRemaining(b);
- }
- },
-
- // Wrap as parallel stream + toArray
- PAR_STREAM_TO_ARRAY(true) {
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- for (Object t : m.apply(source).toArray())
- b.accept((U) t);
- }
- },
-
- // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
- PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- Stream<U> s = m.apply(source);
- Spliterator<U> sp = s.spliterator();
- Stream<U> ss = StreamSupport.stream(() -> sp,
- StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
- | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED), true);
- for (Object t : ss.toArray())
- b.accept((U) t);
- }
- },
-
- // Wrap as parallel stream + toArray and clear SIZED flag
- PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- S_IN pipe1 = (S_IN) OpTestCase.chain(source,
- new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
- Stream<U> pipe2 = m.apply(pipe1);
-
- for (Object t : pipe2.toArray())
- b.accept((U) t);
- }
- },
-
- // Wrap as parallel + collect to list
- PAR_STREAM_COLLECT_TO_LIST(true) {
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- for (U u : m.apply(source).collect(Collectors.toList()))
- b.accept(u);
- }
- },
-
- // Wrap sequential as parallel, + collect to list
- STREAM_TO_PAR_STREAM_COLLECT_TO_LIST(true) {
- public <T, S_IN extends BaseStream<T, S_IN>>
- S_IN getStream(TestData<T, S_IN> data) {
- return data.stream().parallel();
- }
-
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- for (U u : m.apply(source).collect(Collectors.toList()))
- b.accept(u);
- }
- },
-
- // Wrap parallel as sequential,, + collect
- PAR_STREAM_TO_STREAM_COLLECT_TO_LIST(true) {
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- for (U u : m.apply(source).collect(Collectors.toList()))
- b.accept(u);
- }
- },
-
- // Wrap as parallel stream + forEach synchronizing
- PAR_STREAM_FOR_EACH(true, false) {
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- m.apply(source).forEach(e -> {
- synchronized (data) {
- b.accept(e);
- }
- });
- }
- },
-
- // Wrap as parallel stream + forEach synchronizing and clear SIZED flag
- PAR_STREAM_FOR_EACH_CLEAR_SIZED(true, false) {
- <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m) {
- S_IN pipe1 = (S_IN) OpTestCase.chain(source,
- new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
- m.apply(pipe1).forEach(e -> {
- synchronized (data) {
- b.accept(e);
- }
- });
- }
- },
- ;
-
- // The set of scenarios that clean the SIZED flag
- public static final Set<StreamTestScenario> CLEAR_SIZED_SCENARIOS = Collections.unmodifiableSet(
- EnumSet.of(PAR_STREAM_TO_ARRAY_CLEAR_SIZED, PAR_STREAM_FOR_EACH_CLEAR_SIZED));
-
- private final boolean isParallel;
-
- private final boolean isOrdered;
-
- StreamTestScenario(boolean isParallel) {
- this(isParallel, true);
- }
-
- StreamTestScenario(boolean isParallel, boolean isOrdered) {
- this.isParallel = isParallel;
- this.isOrdered = isOrdered;
- }
-
- public StreamShape getShape() {
- return StreamShape.REFERENCE;
- }
-
- public boolean isParallel() {
- return isParallel;
- }
-
- public boolean isOrdered() {
- return isOrdered;
- }
-
- public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
- void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
- try (S_IN source = getStream(data)) {
- run(data, source, b, (Function<S_IN, Stream<U>>) m);
- }
- }
-
- abstract <T, U, S_IN extends BaseStream<T, S_IN>>
- void run(TestData<T, S_IN> data, S_IN source, Consumer<U> b, Function<S_IN, Stream<U>> m);
-
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/TestData.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,355 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.PrimitiveIterator;
-import java.util.Spliterator;
-import java.util.Spliterators;
-import java.util.function.DoubleConsumer;
-import java.util.function.Function;
-import java.util.function.IntConsumer;
-import java.util.function.LongConsumer;
-import java.util.function.Supplier;
-import java.util.function.ToIntFunction;
-
-/** Describes a test data set for use in stream tests */
-public interface TestData<T, S extends BaseStream<T, S>>
- extends Iterable<T> {
-
- default int size() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- default Iterator<T> iterator() {
- return Spliterators.iterator(spliterator());
- }
-
- Spliterator<T> spliterator();
-
- default boolean isOrdered() {
- return spliterator().hasCharacteristics(Spliterator.ORDERED);
- }
-
- StreamShape getShape();
-
- default <A extends Collection<? super T>> A into(A target) {
- spliterator().forEachRemaining(target::add);
- return target;
- }
-
- S stream();
-
- S parallelStream();
-
- public interface OfRef<T> extends TestData<T, Stream<T>> { }
-
- public interface OfInt extends TestData<Integer, IntStream> { }
-
- public interface OfLong extends TestData<Long, LongStream> { }
-
- public interface OfDouble extends TestData<Double, DoubleStream> { }
-
- // @@@ Temporary garbage class to avoid triggering bugs with lambdas in static methods in interfaces
- public static class Factory {
- public static <T> OfRef<T> ofArray(String name, T[] array) {
- return new AbstractTestData.RefTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
- Arrays::spliterator, a -> a.length);
- }
-
- public static <T> OfRef<T> ofCollection(String name, Collection<T> collection) {
- return new AbstractTestData.RefTestData<>(name, collection, Collection::stream, Collection::parallelStream,
- Collection::spliterator, Collection::size);
- }
-
- public static <T> OfRef<T> ofSpinedBuffer(String name, SpinedBuffer<T> buffer) {
- return new AbstractTestData.RefTestData<>(name, buffer,
- b -> StreamSupport.stream(b.spliterator(), false),
- b -> StreamSupport.stream(b.spliterator(), true),
- SpinedBuffer::spliterator,
- b -> (int) b.count());
- }
-
- public static <T> OfRef<T> ofSupplier(String name, Supplier<Stream<T>> supplier) {
- return new AbstractTestData.RefTestData<>(name, supplier,
- Supplier::get,
- s -> s.get().parallel(),
- s -> s.get().spliterator(),
- s -> (int) s.get().spliterator().getExactSizeIfKnown());
- }
-
- public static <T> OfRef<T> ofRefNode(String name, Node<T> node) {
- return new AbstractTestData.RefTestData<>(name, node,
- n -> StreamSupport.stream(n::spliterator, Spliterator.SIZED | Spliterator.ORDERED, false),
- n -> StreamSupport.stream(n::spliterator, Spliterator.SIZED | Spliterator.ORDERED, true),
- Node::spliterator,
- n -> (int) n.count());
- }
-
- // int factories
- public static <T> OfInt ofArray(String name, int[] array) {
- return new AbstractTestData.IntTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
- Arrays::spliterator, a -> a.length);
- }
-
- public static OfInt ofSpinedBuffer(String name, SpinedBuffer.OfInt buffer) {
- return new AbstractTestData.IntTestData<>(name, buffer,
- b -> StreamSupport.intStream(b.spliterator(), false),
- b -> StreamSupport.intStream(b.spliterator(), true),
- SpinedBuffer.OfInt::spliterator,
- b -> (int) b.count());
- }
-
- public static OfInt ofIntSupplier(String name, Supplier<IntStream> supplier) {
- return new AbstractTestData.IntTestData<>(name, supplier,
- Supplier::get,
- s -> s.get().parallel(),
- s -> s.get().spliterator(),
- s -> (int) s.get().spliterator().getExactSizeIfKnown());
- }
-
- public static OfInt ofNode(String name, Node.OfInt node) {
- int characteristics = Spliterator.SIZED | Spliterator.ORDERED;
- return new AbstractTestData.IntTestData<>(name, node,
- n -> StreamSupport.intStream(n::spliterator, characteristics, false),
- n -> StreamSupport.intStream(n::spliterator, characteristics, true),
- Node.OfInt::spliterator,
- n -> (int) n.count());
- }
-
- // long factories
- public static <T> OfLong ofArray(String name, long[] array) {
- return new AbstractTestData.LongTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
- Arrays::spliterator, a -> a.length);
- }
-
- public static OfLong ofSpinedBuffer(String name, SpinedBuffer.OfLong buffer) {
- return new AbstractTestData.LongTestData<>(name, buffer,
- b -> StreamSupport.longStream(b.spliterator(), false),
- b -> StreamSupport.longStream(b.spliterator(), true),
- SpinedBuffer.OfLong::spliterator,
- b -> (int) b.count());
- }
-
- public static OfLong ofLongSupplier(String name, Supplier<LongStream> supplier) {
- return new AbstractTestData.LongTestData<>(name, supplier,
- Supplier::get,
- s -> s.get().parallel(),
- s -> s.get().spliterator(),
- s -> (int) s.get().spliterator().getExactSizeIfKnown());
- }
-
- public static OfLong ofNode(String name, Node.OfLong node) {
- int characteristics = Spliterator.SIZED | Spliterator.ORDERED;
- return new AbstractTestData.LongTestData<>(name, node,
- n -> StreamSupport.longStream(n::spliterator, characteristics, false),
- n -> StreamSupport.longStream(n::spliterator, characteristics, true),
- Node.OfLong::spliterator,
- n -> (int) n.count());
- }
-
- // double factories
- public static <T> OfDouble ofArray(String name, double[] array) {
- return new AbstractTestData.DoubleTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
- Arrays::spliterator, a -> a.length);
- }
-
- public static OfDouble ofSpinedBuffer(String name, SpinedBuffer.OfDouble buffer) {
- return new AbstractTestData.DoubleTestData<>(name, buffer,
- b -> StreamSupport.doubleStream(b.spliterator(), false),
- b -> StreamSupport.doubleStream(b.spliterator(), true),
- SpinedBuffer.OfDouble::spliterator,
- b -> (int) b.count());
- }
-
- public static OfDouble ofDoubleSupplier(String name, Supplier<DoubleStream> supplier) {
- return new AbstractTestData.DoubleTestData<>(name, supplier,
- Supplier::get,
- s -> s.get().parallel(),
- s -> s.get().spliterator(),
- s -> (int) s.get().spliterator().getExactSizeIfKnown());
- }
-
- public static OfDouble ofNode(String name, Node.OfDouble node) {
- int characteristics = Spliterator.SIZED | Spliterator.ORDERED;
- return new AbstractTestData.DoubleTestData<>(name, node,
- n -> StreamSupport.doubleStream(n::spliterator, characteristics, false),
- n -> StreamSupport.doubleStream(n::spliterator, characteristics, true),
- Node.OfDouble::spliterator,
- n -> (int) n.count());
- }
- }
-
-
- abstract class AbstractTestData<T, S extends BaseStream<T, S>,
- T_STATE,
- T_SPLITR extends Spliterator<T>>
- implements TestData<T, S> {
- private final String name;
- private final StreamShape shape;
- protected final T_STATE state;
- private final ToIntFunction<T_STATE> sizeFn;
- private final Function<T_STATE, S> streamFn;
- private final Function<T_STATE, S> parStreamFn;
- private final Function<T_STATE, T_SPLITR> splitrFn;
-
- AbstractTestData(String name,
- StreamShape shape,
- T_STATE state,
- Function<T_STATE, S> streamFn,
- Function<T_STATE, S> parStreamFn,
- Function<T_STATE, T_SPLITR> splitrFn,
- ToIntFunction<T_STATE> sizeFn) {
- this.name = name;
- this.shape = shape;
- this.state = state;
- this.streamFn = streamFn;
- this.parStreamFn = parStreamFn;
- this.splitrFn = splitrFn;
- this.sizeFn = sizeFn;
- }
-
- @Override
- public StreamShape getShape() {
- return shape;
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName() + "[" + name + "]";
- }
-
- @Override
- public int size() {
- return sizeFn.applyAsInt(state);
- }
-
- @Override
- public T_SPLITR spliterator() {
- return splitrFn.apply(state);
- }
-
- @Override
- public S stream() {
- return streamFn.apply(state);
- }
-
- @Override
- public S parallelStream() {
- return parStreamFn.apply(state);
- }
-
- public static class RefTestData<T, I>
- extends AbstractTestData<T, Stream<T>, I, Spliterator<T>>
- implements TestData.OfRef<T> {
-
- protected RefTestData(String name,
- I state,
- Function<I, Stream<T>> streamFn,
- Function<I, Stream<T>> parStreamFn,
- Function<I, Spliterator<T>> splitrFn,
- ToIntFunction<I> sizeFn) {
- super(name, StreamShape.REFERENCE, state, streamFn, parStreamFn, splitrFn, sizeFn);
- }
-
- }
-
- static class IntTestData<I>
- extends AbstractTestData<Integer, IntStream, I, Spliterator.OfInt>
- implements TestData.OfInt {
-
- protected IntTestData(String name,
- I state,
- Function<I, IntStream> streamFn,
- Function<I, IntStream> parStreamFn,
- Function<I, Spliterator.OfInt> splitrFn,
- ToIntFunction<I> sizeFn) {
- super(name, StreamShape.INT_VALUE, state, streamFn, parStreamFn, splitrFn, sizeFn);
- }
-
- @Override
- public PrimitiveIterator.OfInt iterator() {
- return Spliterators.iterator(spliterator());
- }
-
- @Override
- public <A extends Collection<? super Integer>> A into(A target) {
- spliterator().forEachRemaining((IntConsumer) target::add);
- return target;
- }
- }
-
- static class LongTestData<I>
- extends AbstractTestData<Long, LongStream, I, Spliterator.OfLong>
- implements TestData.OfLong {
-
- protected LongTestData(String name,
- I state,
- Function<I, LongStream> streamFn,
- Function<I, LongStream> parStreamFn,
- Function<I, Spliterator.OfLong> splitrFn,
- ToIntFunction<I> sizeFn) {
- super(name, StreamShape.LONG_VALUE, state, streamFn, parStreamFn, splitrFn, sizeFn);
- }
-
- @Override
- public PrimitiveIterator.OfLong iterator() {
- return Spliterators.iterator(spliterator());
- }
-
- @Override
- public <A extends Collection<? super Long>> A into(A target) {
- spliterator().forEachRemaining((LongConsumer) target::add);
- return target;
- }
- }
-
- static class DoubleTestData<I>
- extends AbstractTestData<Double, DoubleStream, I, Spliterator.OfDouble>
- implements OfDouble {
-
- protected DoubleTestData(String name,
- I state,
- Function<I, DoubleStream> streamFn,
- Function<I, DoubleStream> parStreamFn,
- Function<I, Spliterator.OfDouble> splitrFn,
- ToIntFunction<I> sizeFn) {
- super(name, StreamShape.DOUBLE_VALUE, state, streamFn, parStreamFn, splitrFn, sizeFn);
- }
-
- @Override
- public PrimitiveIterator.OfDouble iterator() {
- return Spliterators.iterator(spliterator());
- }
-
- @Override
- public <A extends Collection<? super Double>> A into(A target) {
- spliterator().forEachRemaining((DoubleConsumer) target::add);
- return target;
- }
- }
- }
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/TestFlagExpectedOp.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import org.testng.Assert;
-
-import java.util.EnumSet;
-
-class TestFlagExpectedOp<T> extends FlagDeclaringOp<T> {
-
- static class Builder<T> {
- final int flags;
- StreamShape shape = StreamShape.REFERENCE;
-
- EnumSet<StreamOpFlag> known = EnumSet.noneOf(StreamOpFlag.class);
- EnumSet<StreamOpFlag> preserve = EnumSet.noneOf(StreamOpFlag.class);
- EnumSet<StreamOpFlag> notKnown = EnumSet.noneOf(StreamOpFlag.class);
-
- Builder(int flags) {
- this.flags = flags;
- }
-
- Builder<T> known(EnumSet<StreamOpFlag> known) {
- this.known = known;
- return this;
- }
-
- Builder<T> preserve(EnumSet<StreamOpFlag> preserve) {
- this.preserve = preserve;
- return this;
- }
-
- Builder<T> notKnown(EnumSet<StreamOpFlag> notKnown) {
- this.notKnown = notKnown;
- return this;
- }
-
- Builder<T> shape(StreamShape shape) {
- this.shape = shape;
- return this;
- }
-
- TestFlagExpectedOp<T> build() {
- return new TestFlagExpectedOp<>(flags, known, preserve, notKnown, shape);
- }
- }
-
- final EnumSet<StreamOpFlag> known;
- final EnumSet<StreamOpFlag> preserve;
- final EnumSet<StreamOpFlag> notKnown;
- final StreamShape shape;
-
- TestFlagExpectedOp(int flags,
- EnumSet<StreamOpFlag> known,
- EnumSet<StreamOpFlag> preserve,
- EnumSet<StreamOpFlag> notKnown) {
- this(flags, known, preserve, notKnown, StreamShape.REFERENCE);
- }
-
- TestFlagExpectedOp(int flags,
- EnumSet<StreamOpFlag> known,
- EnumSet<StreamOpFlag> preserve,
- EnumSet<StreamOpFlag> notKnown,
- StreamShape shape) {
- super(flags);
- this.known = known;
- this.preserve = preserve;
- this.notKnown = notKnown;
- this.shape = shape;
- }
-
- @Override
- public StreamShape outputShape() {
- return shape;
- }
-
- @Override
- public StreamShape inputShape() {
- return shape;
- }
-
- @Override
- @SuppressWarnings({"rawtypes", "unchecked"})
- public Sink<T> opWrapSink(int flags, boolean parallel, Sink upstream) {
- assertFlags(flags);
- return upstream;
- }
-
- private void assertFlags(int flags) {
- for (StreamOpFlag f : known) {
- Assert.assertTrue(f.isKnown(flags),
- String.format("Flag %s is not known, but should be known.", f.toString()));
- }
-
- for (StreamOpFlag f : preserve) {
- Assert.assertTrue(f.isPreserved(flags),
- String.format("Flag %s is not preserved, but should be preserved.", f.toString()));
- }
-
- for (StreamOpFlag f : notKnown) {
- Assert.assertFalse(f.isKnown(flags),
- String.format("Flag %s is known, but should be not known.", f.toString()));
- }
- }
-}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/ThowableHelper.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertTrue;
-
-public final class ThowableHelper {
-
- public static void checkException(Class<? extends Exception> ce, Runnable r) {
- Exception caught = null;
- try {
- r.run();
- } catch (Exception e) {
- caught = e;
- }
-
- assertNotNull(caught);
- assertTrue(ce.isInstance(caught));
- }
-
- public static void checkNPE(Runnable r) {
- checkException(NullPointerException.class, r);
- }
-
- public static void checkISE(Runnable r) {
- checkException(IllegalStateException.class, r);
- }
-}
--- a/jdk/test/java/util/stream/boottest/TEST.properties Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/util/stream/boottest/TEST.properties Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
# This file identifies root(s) of the test-ng hierarchy.
-TestNG.dirs = .
-bootclasspath.dirs = .
-lib.dirs = /java/util/stream/bootlib
+TestNG.dirs = java.base
+bootclasspath.dirs = java.base
+lib.dirs = /java/util/stream/bootlib/java.base
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/boottest/java.base/java/util/stream/DoubleNodeTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.PrimitiveIterator;
+import java.util.Spliterators;
+import java.util.function.Function;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+@Test
+public class DoubleNodeTest extends OpTestCase {
+
+ @DataProvider(name = "nodes")
+ public Object[][] createSizes() {
+ List<Object[]> params = new ArrayList<>();
+
+ for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
+ double[] array = new double[size];
+ for (int i = 0; i < array.length; i++) {
+ array[i] = i;
+ }
+
+ List<Node<Double>> nodes = new ArrayList<>();
+
+ nodes.add(Nodes.node(array));
+ nodes.add(degenerateTree(Spliterators.iterator(Arrays.spliterator(array))));
+ nodes.add(tree(toList(array), l -> Nodes.node(toDoubleArray(l))));
+ nodes.add(fill(array, Nodes.doubleBuilder(array.length)));
+ nodes.add(fill(array, Nodes.doubleBuilder()));
+
+ for (Node<Double> node : nodes) {
+ params.add(new Object[]{array, node});
+ }
+
+ }
+
+ return params.toArray(new Object[0][]);
+ }
+
+ private static void assertEqualsListDoubleArray(List<Double> list, double[] array) {
+ assertEquals(list.size(), array.length);
+ for (int i = 0; i < array.length; i++)
+ assertEquals(array[i], list.get(i));
+ }
+
+ private List<Double> toList(double[] a) {
+ List<Double> l = new ArrayList<>();
+ for (double i : a) {
+ l.add(i);
+ }
+
+ return l;
+ }
+
+ private double[] toDoubleArray(List<Double> l) {
+ double[] a = new double[l.size()];
+
+ int i = 0;
+ for (Double e : l) {
+ a[i++] = e;
+ }
+ return a;
+ }
+
+ private Node.OfDouble fill(double[] array, Node.Builder.OfDouble nb) {
+ nb.begin(array.length);
+ for (double i : array)
+ nb.accept(i);
+ nb.end();
+ return nb.build();
+ }
+
+ private Node.OfDouble degenerateTree(PrimitiveIterator.OfDouble it) {
+ if (!it.hasNext()) {
+ return Nodes.node(new double[0]);
+ }
+
+ double i = it.nextDouble();
+ if (it.hasNext()) {
+ return new Nodes.ConcNode.OfDouble(Nodes.node(new double[] {i}), degenerateTree(it));
+ }
+ else {
+ return Nodes.node(new double[] {i});
+ }
+ }
+
+ private Node.OfDouble tree(List<Double> l, Function<List<Double>, Node.OfDouble> m) {
+ if (l.size() < 3) {
+ return m.apply(l);
+ }
+ else {
+ return new Nodes.ConcNode.OfDouble(
+ tree(l.subList(0, l.size() / 2), m),
+ tree(l.subList(l.size() / 2, l.size()), m));
+ }
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testAsArray(double[] array, Node.OfDouble n) {
+ assertEquals(n.asPrimitiveArray(), array);
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testFlattenAsArray(double[] array, Node.OfDouble n) {
+ assertEquals(Nodes.flattenDouble(n).asPrimitiveArray(), array);
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testCopyTo(double[] array, Node.OfDouble n) {
+ double[] copy = new double[(int) n.count()];
+ n.copyInto(copy, 0);
+
+ assertEquals(copy, array);
+ }
+
+ @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
+ public void testForEach(double[] array, Node.OfDouble n) {
+ List<Double> l = new ArrayList<>((int) n.count());
+ n.forEach((double e) -> {
+ l.add(e);
+ });
+
+ assertEqualsListDoubleArray(l, array);
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testStreams(double[] array, Node.OfDouble n) {
+ TestData.OfDouble data = TestData.Factory.ofNode("Node", n);
+
+ exerciseOps(data, s -> s);
+
+ exerciseTerminalOps(data, s -> s.toArray());
+ }
+
+ @Test(dataProvider = "nodes", groups={ "serialization-hostile" })
+ // throws SOE on serialization of DoubleConcNode[size=1000]
+ public void testSpliterator(double[] array, Node.OfDouble n) {
+ SpliteratorTestHelper.testDoubleSpliterator(n::spliterator);
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testTruncate(double[] array, Node.OfDouble n) {
+ int[] nums = new int[] { 0, 1, array.length / 2, array.length - 1, array.length };
+ for (int start : nums)
+ for (int end : nums) {
+ if (start < 0 || end < 0 || end < start || end > array.length)
+ continue;
+ Node.OfDouble slice = n.truncate(start, end, Double[]::new);
+ double[] asArray = slice.asPrimitiveArray();
+ for (int k = start; k < end; k++)
+ assertEquals(array[k], asArray[k - start]);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/boottest/java.base/java/util/stream/FlagOpTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.function.Supplier;
+
+import static java.util.stream.LambdaTestHelpers.countTo;
+
+@Test
+public class FlagOpTest extends OpTestCase {
+
+ @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+ public void testFlagsPassThrough(String name, TestData<Integer, Stream<Integer>> data) {
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ TestFlagPassThroughOp<Integer>[] ops = new TestFlagPassThroughOp[3];
+ ops[0] = new TestFlagPassThroughOp<>();
+ ops[1] = new TestFlagPassThroughOp<>();
+ ops[2] = new TestFlagPassThroughOp<>();
+
+ ops[0].set(null, ops[1]);
+ ops[1].set(ops[0], ops[2]);
+ ops[2].set(ops[1], null);
+
+ withData(data).ops(ops).exercise();
+ }
+
+ static class TestFlagPassThroughOp<T> extends FlagDeclaringOp<T> {
+ TestFlagPassThroughOp<T> upstream;
+ TestFlagPassThroughOp<T> downstream;
+
+ TestFlagPassThroughOp() {
+ super(0);
+ }
+
+ void set(TestFlagPassThroughOp<T> upstream, TestFlagPassThroughOp<T> downstream) {
+ this.upstream = upstream;
+ this.downstream = downstream;
+ }
+
+ int wrapFlags;
+
+ @Override
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public Sink<T> opWrapSink(int flags, boolean parallel, Sink sink) {
+ this.wrapFlags = flags;
+
+ if (downstream != null) {
+ assertTrue(flags == downstream.wrapFlags);
+ }
+
+ return sink;
+ }
+ }
+
+ public void testFlagsClearAllSet() {
+ int clearAllFlags = 0;
+ for (StreamOpFlag f : EnumSet.allOf(StreamOpFlag.class)) {
+ if (f.isStreamFlag()) {
+ clearAllFlags |= f.clear();
+ }
+ }
+
+ EnumSet<StreamOpFlag> known = EnumSet.noneOf(StreamOpFlag.class);
+ EnumSet<StreamOpFlag> notKnown = StreamOpFlagTestHelper.allStreamFlags();
+
+ List<FlagDeclaringOp<Integer>> ops = new ArrayList<>();
+ ops.add(new FlagDeclaringOp<>(clearAllFlags));
+ for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+ if (f.canSet(StreamOpFlag.Type.OP)) {
+ ops.add(new TestFlagExpectedOp<>(f.set(),
+ known.clone(),
+ EnumSet.noneOf(StreamOpFlag.class),
+ notKnown.clone()));
+ known.add(f);
+ notKnown.remove(f);
+ }
+ }
+ ops.add(new TestFlagExpectedOp<>(0,
+ known.clone(),
+ EnumSet.noneOf(StreamOpFlag.class),
+ notKnown.clone()));
+
+ TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+ @SuppressWarnings("rawtypes")
+ FlagDeclaringOp[] opsArray = ops.toArray(new FlagDeclaringOp[ops.size()]);
+
+ withData(data).ops(opsArray).
+ without(StreamTestScenario.CLEAR_SIZED_SCENARIOS).
+ exercise();
+ }
+
+ public void testFlagsSetAllClear() {
+ EnumSet<StreamOpFlag> known = StreamOpFlagTestHelper.allStreamFlags();
+ int setAllFlags = 0;
+ for (StreamOpFlag f : EnumSet.allOf(StreamOpFlag.class)) {
+ if (f.isStreamFlag()) {
+ if (f.canSet(StreamOpFlag.Type.OP)) {
+ setAllFlags |= f.set();
+ } else {
+ known.remove(f);
+ }
+ }
+ }
+
+ EnumSet<StreamOpFlag> notKnown = EnumSet.noneOf(StreamOpFlag.class);
+
+ List<FlagDeclaringOp<Integer>> ops = new ArrayList<>();
+ ops.add(new FlagDeclaringOp<>(setAllFlags));
+ for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+ ops.add(new TestFlagExpectedOp<>(f.clear(),
+ known.clone(),
+ EnumSet.noneOf(StreamOpFlag.class),
+ notKnown.clone()));
+ known.remove(f);
+ notKnown.add(f);
+ }
+ ops.add(new TestFlagExpectedOp<>(0,
+ known.clone(),
+ EnumSet.noneOf(StreamOpFlag.class),
+ notKnown.clone()));
+
+ TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+ @SuppressWarnings("rawtypes")
+ FlagDeclaringOp[] opsArray = ops.toArray(new FlagDeclaringOp[ops.size()]);
+
+
+ withData(data).ops(opsArray).
+ without(StreamTestScenario.CLEAR_SIZED_SCENARIOS).
+ exercise();
+ }
+
+ public void testFlagsParallelCollect() {
+ testFlagsSetSequence(CollectorOps::collector);
+ }
+
+ private void testFlagsSetSequence(Supplier<StatefulTestOp<Integer>> cf) {
+ EnumSet<StreamOpFlag> known = EnumSet.of(StreamOpFlag.ORDERED, StreamOpFlag.SIZED);
+ EnumSet<StreamOpFlag> preserve = EnumSet.of(StreamOpFlag.DISTINCT, StreamOpFlag.SORTED);
+
+ List<IntermediateTestOp<Integer, Integer>> ops = new ArrayList<>();
+ for (StreamOpFlag f : EnumSet.of(StreamOpFlag.DISTINCT, StreamOpFlag.SORTED)) {
+ ops.add(cf.get());
+ ops.add(new TestFlagExpectedOp<>(f.set(),
+ known.clone(),
+ preserve.clone(),
+ EnumSet.noneOf(StreamOpFlag.class)));
+ known.add(f);
+ preserve.remove(f);
+ }
+ ops.add(cf.get());
+ ops.add(new TestFlagExpectedOp<>(0,
+ known.clone(),
+ preserve.clone(),
+ EnumSet.noneOf(StreamOpFlag.class)));
+
+ TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+ @SuppressWarnings("rawtypes")
+ IntermediateTestOp[] opsArray = ops.toArray(new IntermediateTestOp[ops.size()]);
+
+ withData(data).ops(opsArray).
+ without(StreamTestScenario.CLEAR_SIZED_SCENARIOS).
+ exercise();
+ }
+
+
+ public void testFlagsClearParallelCollect() {
+ testFlagsClearSequence(CollectorOps::collector);
+ }
+
+ protected void testFlagsClearSequence(Supplier<StatefulTestOp<Integer>> cf) {
+ EnumSet<StreamOpFlag> known = EnumSet.of(StreamOpFlag.ORDERED, StreamOpFlag.SIZED);
+ EnumSet<StreamOpFlag> preserve = EnumSet.of(StreamOpFlag.DISTINCT, StreamOpFlag.SORTED);
+ EnumSet<StreamOpFlag> notKnown = EnumSet.noneOf(StreamOpFlag.class);
+
+ List<IntermediateTestOp<Integer, Integer>> ops = new ArrayList<>();
+ for (StreamOpFlag f : EnumSet.of(StreamOpFlag.ORDERED, StreamOpFlag.DISTINCT, StreamOpFlag.SORTED)) {
+ ops.add(cf.get());
+ ops.add(new TestFlagExpectedOp<>(f.clear(),
+ known.clone(),
+ preserve.clone(),
+ notKnown.clone()));
+ known.remove(f);
+ preserve.remove(f);
+ notKnown.add(f);
+ }
+ ops.add(cf.get());
+ ops.add(new TestFlagExpectedOp<>(0,
+ known.clone(),
+ preserve.clone(),
+ notKnown.clone()));
+
+ TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+ @SuppressWarnings("rawtypes")
+ IntermediateTestOp[] opsArray = ops.toArray(new IntermediateTestOp[ops.size()]);
+
+ withData(data).ops(opsArray).
+ without(StreamTestScenario.CLEAR_SIZED_SCENARIOS).
+ exercise();
+ }
+
+ public void testFlagsSizedOrderedParallelCollect() {
+ EnumSet<StreamOpFlag> parKnown = EnumSet.of(StreamOpFlag.SIZED);
+ EnumSet<StreamOpFlag> serKnown = parKnown.clone();
+
+ List<IntermediateTestOp<Integer, Integer>> ops = new ArrayList<>();
+ for (StreamOpFlag f : parKnown) {
+ ops.add(CollectorOps.collector());
+ ops.add(new ParSerTestFlagExpectedOp<>(f.clear(),
+ parKnown,
+ serKnown));
+ serKnown.remove(f);
+ }
+ ops.add(CollectorOps.collector());
+ ops.add(new ParSerTestFlagExpectedOp<>(0,
+ parKnown,
+ EnumSet.noneOf(StreamOpFlag.class)));
+
+ TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+ @SuppressWarnings("rawtypes")
+ IntermediateTestOp[] opsArray = ops.toArray(new IntermediateTestOp[ops.size()]);
+
+ withData(data).ops(opsArray).exercise();
+ }
+
+ static class ParSerTestFlagExpectedOp<T> extends FlagDeclaringOp<T> {
+ final EnumSet<StreamOpFlag> parKnown;
+ final EnumSet<StreamOpFlag> serKnown;
+
+ ParSerTestFlagExpectedOp(int flags, EnumSet<StreamOpFlag> known, EnumSet<StreamOpFlag> serKnown) {
+ super(flags);
+ this.parKnown = known;
+ this.serKnown = serKnown;
+ }
+
+ @Override
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public Sink<T> opWrapSink(int flags, boolean parallel, Sink upstream) {
+ assertFlags(flags, parallel);
+ return upstream;
+ }
+
+ protected void assertFlags(int flags, boolean parallel) {
+ if (parallel) {
+ for (StreamOpFlag f : parKnown) {
+ Assert.assertTrue(f.isKnown(flags), String.format("Flag %s is not known, but should be known.", f.toString()));
+ }
+
+ } else {
+ for (StreamOpFlag f : serKnown) {
+ Assert.assertTrue(f.isKnown(flags), String.format("Flag %s is not known, but should be known.", f.toString()));
+ }
+
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/boottest/java.base/java/util/stream/IntNodeTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.PrimitiveIterator;
+import java.util.Spliterators;
+import java.util.function.Function;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+@Test
+public class IntNodeTest extends OpTestCase {
+
+ @DataProvider(name = "nodes")
+ public Object[][] createSizes() {
+ List<Object[]> params = new ArrayList<>();
+
+ for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
+ int[] array = new int[size];
+ for (int i = 0; i < array.length; i++) {
+ array[i] = i;
+ }
+
+ List<Node<Integer>> nodes = new ArrayList<>();
+
+ nodes.add(Nodes.node(array));
+ nodes.add(degenerateTree(Spliterators.iterator(Arrays.spliterator(array))));
+ nodes.add(tree(toList(array), l -> Nodes.node(toIntArray(l))));
+ nodes.add(fill(array, Nodes.intBuilder(array.length)));
+ nodes.add(fill(array, Nodes.intBuilder()));
+
+ for (Node<Integer> node : nodes) {
+ params.add(new Object[]{array, node});
+ }
+
+ }
+
+ return params.toArray(new Object[0][]);
+ }
+
+ private static void assertEqualsListIntArray(List<Integer> list, int[] array) {
+ assertEquals(list.size(), array.length);
+ for (int i = 0; i < array.length; i++)
+ assertEquals(array[i], (int) list.get(i));
+ }
+
+ private List<Integer> toList(int[] a) {
+ List<Integer> l = new ArrayList<>();
+ for (int i : a) {
+ l.add(i);
+ }
+
+ return l;
+ }
+
+ private int[] toIntArray(List<Integer> l) {
+ int[] a = new int[l.size()];
+
+ int i = 0;
+ for (Integer e : l) {
+ a[i++] = e;
+ }
+ return a;
+ }
+
+ private Node.OfInt fill(int[] array, Node.Builder.OfInt nb) {
+ nb.begin(array.length);
+ for (int i : array)
+ nb.accept(i);
+ nb.end();
+ return nb.build();
+ }
+
+ private Node.OfInt degenerateTree(PrimitiveIterator.OfInt it) {
+ if (!it.hasNext()) {
+ return Nodes.node(new int[0]);
+ }
+
+ int i = it.nextInt();
+ if (it.hasNext()) {
+ return new Nodes.ConcNode.OfInt(Nodes.node(new int[] {i}), degenerateTree(it));
+ }
+ else {
+ return Nodes.node(new int[] {i});
+ }
+ }
+
+ private Node.OfInt tree(List<Integer> l, Function<List<Integer>, Node.OfInt> m) {
+ if (l.size() < 3) {
+ return m.apply(l);
+ }
+ else {
+ return new Nodes.ConcNode.OfInt(
+ tree(l.subList(0, l.size() / 2), m),
+ tree(l.subList(l.size() / 2, l.size()), m));
+ }
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testAsArray(int[] array, Node.OfInt n) {
+ assertEquals(n.asPrimitiveArray(), array);
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testFlattenAsArray(int[] array, Node.OfInt n) {
+ assertEquals(Nodes.flattenInt(n).asPrimitiveArray(), array);
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testCopyTo(int[] array, Node.OfInt n) {
+ int[] copy = new int[(int) n.count()];
+ n.copyInto(copy, 0);
+
+ assertEquals(copy, array);
+ }
+
+ @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
+ public void testForEach(int[] array, Node.OfInt n) {
+ List<Integer> l = new ArrayList<>((int) n.count());
+ n.forEach((int e) -> {
+ l.add(e);
+ });
+
+ assertEqualsListIntArray(l, array);
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testStreams(int[] array, Node.OfInt n) {
+ TestData.OfInt data = TestData.Factory.ofNode("Node", n);
+
+ exerciseOps(data, s -> s);
+ exerciseTerminalOps(data, s -> s.toArray());
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testSpliterator(int[] array, Node.OfInt n) {
+ SpliteratorTestHelper.testIntSpliterator(n::spliterator);
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testTruncate(int[] array, Node.OfInt n) {
+ int[] nums = new int[] { 0, 1, array.length / 2, array.length - 1, array.length };
+ for (int start : nums)
+ for (int end : nums) {
+ if (start < 0 || end < 0 || end < start || end > array.length)
+ continue;
+ Node.OfInt slice = n.truncate(start, end, Integer[]::new);
+ int[] asArray = slice.asPrimitiveArray();
+ for (int k = start; k < end; k++)
+ assertEquals(array[k], asArray[k - start]);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/boottest/java.base/java/util/stream/LongNodeTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.PrimitiveIterator;
+import java.util.Spliterators;
+import java.util.function.Function;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+@Test
+public class LongNodeTest extends OpTestCase {
+
+ @DataProvider(name = "nodes")
+ public Object[][] createSizes() {
+ List<Object[]> params = new ArrayList<>();
+
+ for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
+ long[] array = new long[size];
+ for (int i = 0; i < array.length; i++) {
+ array[i] = i;
+ }
+
+ List<Node<Long>> nodes = new ArrayList<>();
+
+ nodes.add(Nodes.node(array));
+ nodes.add(degenerateTree(Spliterators.iterator(Arrays.spliterator(array))));
+ nodes.add(tree(toList(array), l -> Nodes.node(toLongArray(l))));
+ nodes.add(fill(array, Nodes.longBuilder(array.length)));
+ nodes.add(fill(array, Nodes.longBuilder()));
+
+ for (Node<Long> node : nodes) {
+ params.add(new Object[]{array, node});
+ }
+
+ }
+
+ return params.toArray(new Object[0][]);
+ }
+
+ private static void assertEqualsListLongArray(List<Long> list, long[] array) {
+ assertEquals(list.size(), array.length);
+ for (int i = 0; i < array.length; i++)
+ assertEquals(array[i], (long) list.get(i));
+ }
+
+ private List<Long> toList(long[] a) {
+ List<Long> l = new ArrayList<>();
+ for (long i : a) {
+ l.add(i);
+ }
+
+ return l;
+ }
+
+ private long[] toLongArray(List<Long> l) {
+ long[] a = new long[l.size()];
+
+ int i = 0;
+ for (Long e : l) {
+ a[i++] = e;
+ }
+ return a;
+ }
+
+ private Node.OfLong fill(long[] array, Node.Builder.OfLong nb) {
+ nb.begin(array.length);
+ for (long i : array)
+ nb.accept(i);
+ nb.end();
+ return nb.build();
+ }
+
+ private Node.OfLong degenerateTree(PrimitiveIterator.OfLong it) {
+ if (!it.hasNext()) {
+ return Nodes.node(new long[0]);
+ }
+
+ long i = it.nextLong();
+ if (it.hasNext()) {
+ return new Nodes.ConcNode.OfLong(Nodes.node(new long[] {i}), degenerateTree(it));
+ }
+ else {
+ return Nodes.node(new long[] {i});
+ }
+ }
+
+ private Node.OfLong tree(List<Long> l, Function<List<Long>, Node.OfLong> m) {
+ if (l.size() < 3) {
+ return m.apply(l);
+ }
+ else {
+ return new Nodes.ConcNode.OfLong(
+ tree(l.subList(0, l.size() / 2), m),
+ tree(l.subList(l.size() / 2, l.size()), m));
+ }
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testAsArray(long[] array, Node.OfLong n) {
+ assertEquals(n.asPrimitiveArray(), array);
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testFlattenAsArray(long[] array, Node.OfLong n) {
+ assertEquals(Nodes.flattenLong(n).asPrimitiveArray(), array);
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testCopyTo(long[] array, Node.OfLong n) {
+ long[] copy = new long[(int) n.count()];
+ n.copyInto(copy, 0);
+
+ assertEquals(copy, array);
+ }
+
+ @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
+ public void testForEach(long[] array, Node.OfLong n) {
+ List<Long> l = new ArrayList<>((int) n.count());
+ n.forEach((long e) -> {
+ l.add(e);
+ });
+
+ assertEqualsListLongArray(l, array);
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testStreams(long[] array, Node.OfLong n) {
+ TestData.OfLong data = TestData.Factory.ofNode("Node", n);
+
+ exerciseOps(data, s -> s);
+
+ exerciseTerminalOps(data, s -> s.toArray());
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testSpliterator(long[] array, Node.OfLong n) {
+ SpliteratorTestHelper.testLongSpliterator(n::spliterator);
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testTruncate(long[] array, Node.OfLong n) {
+ int[] nums = new int[] { 0, 1, array.length / 2, array.length - 1, array.length };
+ for (int start : nums)
+ for (int end : nums) {
+ if (start < 0 || end < 0 || end < start || end > array.length)
+ continue;
+ Node.OfLong slice = n.truncate(start, end, Long[]::new);
+ long[] asArray = slice.asPrimitiveArray();
+ for (int k = start; k < end; k++)
+ assertEquals(array[k], asArray[k - start]);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/boottest/java.base/java/util/stream/NodeBuilderTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.DoubleConsumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static java.util.stream.LambdaTestHelpers.assertContents;
+import static java.util.stream.LambdaTestHelpers.countTo;
+import static org.testng.Assert.assertEquals;
+
+@Test
+public class NodeBuilderTest {
+
+ List<Integer> sizes = Arrays.asList(0, 1, 4, 16, 256,
+ 1023, 1024, 1025,
+ 2047, 2048, 2049,
+ 1024 * 32 - 1, 1024 * 32, 1024 * 32 + 1);
+
+ @DataProvider(name = "Node.Builder")
+ public Object[][] createNodeBuilders() {
+ List<List<Integer>> ls = new ArrayList<>();
+ for (int size : sizes) {
+ ls.add(countTo(size));
+ }
+
+ List<Function<Integer, Node.Builder<Integer>>> ms = Arrays.asList(
+ s -> Nodes.builder(),
+ s -> Nodes.builder(s, LambdaTestHelpers.integerArrayGenerator)
+ );
+
+ Object[][] params = new Object[ls.size() * ms.size()][];
+ int i = 0;
+ for (List<Integer> l : ls) {
+ for (Function<Integer, Node.Builder<Integer>> m : ms) {
+ params[i++] = new Object[]{l, m};
+ }
+ }
+
+ return params;
+ }
+
+ @Test(dataProvider = "Node.Builder", groups = { "serialization-hostile" })
+ public void testIteration(List<Integer> l, Function<Integer, Node.Builder<Integer>> m) {
+ Node.Builder<Integer> nb = m.apply(l.size());
+ nb.begin(l.size());
+ for (Integer i : l) {
+ nb.accept(i);
+ }
+ nb.end();
+
+ Node<Integer> n = nb.build();
+ assertEquals(n.count(), l.size());
+
+ {
+ List<Integer> _l = new ArrayList<>();
+ n.forEach(_l::add);
+
+ assertContents(_l, l);
+ }
+ }
+
+ // Node.Builder.OfInt
+
+ @DataProvider(name = "Node.Builder<Integer>")
+ public Object[][] createIntNodeBuilders() {
+ List<List<Integer>> ls = new ArrayList<>();
+ for (int size : sizes) {
+ ls.add(countTo(size));
+ }
+
+ List<Function<Integer, Node.Builder<Integer>>> ms = Arrays.asList(
+ s -> Nodes.intBuilder(),
+ s -> Nodes.intBuilder(s)
+ );
+
+ Object[][] params = new Object[ls.size() * ms.size()][];
+ int i = 0;
+ for (List<Integer> l : ls) {
+ for (Function<Integer, Node.Builder<Integer>> m : ms) {
+ params[i++] = new Object[]{l, m};
+ }
+ }
+
+ return params;
+ }
+
+ @Test(dataProvider = "Node.Builder<Integer>", groups = { "serialization-hostile" })
+ public void testIntIteration(List<Integer> l, Function<Integer, Node.Builder.OfInt> m) {
+ Node.Builder.OfInt nb = m.apply(l.size());
+ nb.begin(l.size());
+ for (Integer i : l) {
+ nb.accept((int) i);
+ }
+ nb.end();
+
+ Node.OfInt n = nb.build();
+ assertEquals(n.count(), l.size());
+
+ {
+ List<Integer> _l = new ArrayList<>();
+ n.forEach((IntConsumer) _l::add);
+
+ assertContents(_l, l);
+ }
+
+ }
+
+ // Node.Builder.OfLong
+
+ @DataProvider(name = "Node.Builder<Long>")
+ public Object[][] createLongNodeBuilders() {
+ List<List<Long>> ls = new ArrayList<>();
+ for (int size : sizes) {
+ List<Long> l = new ArrayList<>();
+ for (long i = 0; i < size; i++) {
+ l.add(i);
+ }
+ ls.add(l);
+ }
+
+ List<Function<Integer, Node.Builder<Long>>> ms = Arrays.asList(
+ s -> Nodes.longBuilder(),
+ s -> Nodes.longBuilder(s)
+ );
+
+ Object[][] params = new Object[ls.size() * ms.size()][];
+ int i = 0;
+ for (List<Long> l : ls) {
+ for (Function<Integer, Node.Builder<Long>> m : ms) {
+ params[i++] = new Object[]{l, m};
+ }
+ }
+
+ return params;
+ }
+
+ @Test(dataProvider = "Node.Builder<Long>")
+ public void testLongIteration(List<Long> l, Function<Integer, Node.Builder.OfLong> m) {
+ Node.Builder.OfLong nb = m.apply(l.size());
+ nb.begin(l.size());
+ for (Long i : l) {
+ nb.accept((long) i);
+ }
+ nb.end();
+
+ Node.OfLong n = nb.build();
+ assertEquals(n.count(), l.size());
+
+ {
+ List<Long> _l = new ArrayList<>();
+ n.forEach((LongConsumer) _l::add);
+
+ assertContents(_l, l);
+ }
+
+ }
+
+ // Node.Builder.OfDouble
+
+ @DataProvider(name = "Node.Builder<Double>")
+ public Object[][] createDoubleNodeBuilders() {
+ List<List<Double>> ls = new ArrayList<>();
+ for (int size : sizes) {
+ List<Double> l = new ArrayList<>();
+ for (long i = 0; i < size; i++) {
+ l.add((double) i);
+ }
+ ls.add(l);
+ }
+
+ List<Function<Integer, Node.Builder<Double>>> ms = Arrays.asList(
+ s -> Nodes.doubleBuilder(),
+ s -> Nodes.doubleBuilder(s)
+ );
+
+ Object[][] params = new Object[ls.size() * ms.size()][];
+ int i = 0;
+ for (List<Double> l : ls) {
+ for (Function<Integer, Node.Builder<Double>> m : ms) {
+ params[i++] = new Object[]{l, m};
+ }
+ }
+
+ return params;
+ }
+
+ @Test(dataProvider = "Node.Builder<Double>")
+ public void testDoubleIteration(List<Double> l, Function<Integer, Node.Builder.OfDouble> m) {
+ Node.Builder.OfDouble nb = m.apply(l.size());
+ nb.begin(l.size());
+ for (Double i : l) {
+ nb.accept((double) i);
+ }
+ nb.end();
+
+ Node.OfDouble n = nb.build();
+ assertEquals(n.count(), l.size());
+
+ {
+ List<Double> _l = new ArrayList<>();
+ n.forEach((DoubleConsumer) _l::add);
+
+ assertContents(_l, l);
+ }
+
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/boottest/java.base/java/util/stream/NodeTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Function;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+@Test
+public class NodeTest extends OpTestCase {
+
+ @DataProvider(name = "nodes")
+ public Object[][] createSizes() {
+ List<Object[]> params = new ArrayList<>();
+
+ for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
+ Integer[] array = new Integer[size];
+ for (int i = 0; i < array.length; i++) {
+ array[i] = i;
+ }
+
+ List<Node<Integer>> nodes = new ArrayList<>();
+ nodes.add(Nodes.node(array));
+ nodes.add(Nodes.node(Arrays.asList(array)));
+ nodes.add(degenerateTree(Arrays.asList(array).iterator()));
+ nodes.add(tree(Arrays.asList(array), l -> Nodes.node(l.toArray(new Integer[l.size()]))));
+ nodes.add(tree(Arrays.asList(array), l -> Nodes.node(l)));
+ nodes.add(fill(array, Nodes.builder(array.length, LambdaTestHelpers.integerArrayGenerator)));
+ nodes.add(fill(array, Nodes.builder()));
+
+ for (int i = 0; i < nodes.size(); i++) {
+ params.add(new Object[]{array, nodes.get(i)});
+ }
+
+ }
+
+ return params.toArray(new Object[0][]);
+ }
+
+ Node<Integer> fill(Integer[] array, Node.Builder<Integer> nb) {
+ nb.begin(array.length);
+ for (Integer i : array) {
+ nb.accept(i);
+ }
+ nb.end();
+ return nb.build();
+ }
+
+ Node<Integer> degenerateTree(Iterator<Integer> it) {
+ if (!it.hasNext()) {
+ return Nodes.node(Collections.emptyList());
+ }
+
+ Integer i = it.next();
+ if (it.hasNext()) {
+ return new Nodes.ConcNode<Integer>(Nodes.node(new Integer[] {i}), degenerateTree(it));
+ }
+ else {
+ return Nodes.node(new Integer[]{i});
+ }
+ }
+
+ Node<Integer> tree(List<Integer> l, Function<List<Integer>, Node<Integer>> m) {
+ if (l.size() < 3) {
+ return m.apply(l);
+ }
+ else {
+ return new Nodes.ConcNode<>(
+ tree(l.subList(0, l.size() / 2), m),
+ tree(l.subList(l.size() / 2, l.size()), m ));
+ }
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testAsArray(Integer[] array, Node<Integer> n) {
+ assertEquals(n.asArray(LambdaTestHelpers.integerArrayGenerator), array);
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testFlattenAsArray(Integer[] array, Node<Integer> n) {
+ assertEquals(Nodes.flatten(n, LambdaTestHelpers.integerArrayGenerator)
+ .asArray(LambdaTestHelpers.integerArrayGenerator), array);
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testCopyTo(Integer[] array, Node<Integer> n) {
+ Integer[] copy = new Integer[(int) n.count()];
+ n.copyInto(copy, 0);
+
+ assertEquals(copy, array);
+ }
+
+ @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
+ public void testForEach(Integer[] array, Node<Integer> n) {
+ List<Integer> l = new ArrayList<>((int) n.count());
+ n.forEach(e -> l.add(e));
+
+ assertEquals(l.toArray(), array);
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testStreams(Integer[] array, Node<Integer> n) {
+ TestData<Integer, Stream<Integer>> data = TestData.Factory.ofRefNode("Node", n);
+
+ exerciseOps(data, s -> s);
+
+ exerciseTerminalOps(data, s -> s.toArray());
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testSpliterator(Integer[] array, Node<Integer> n) {
+ SpliteratorTestHelper.testSpliterator(n::spliterator);
+ }
+
+ @Test(dataProvider = "nodes")
+ public void testTruncate(Integer[] array, Node<Integer> n) {
+ int[] nums = new int[] { 0, 1, array.length / 2, array.length - 1, array.length };
+ for (int start : nums)
+ for (int end : nums) {
+ if (start < 0 || end < 0 || end < start || end > array.length)
+ continue;
+ Node<Integer> slice = n.truncate(start, end, Integer[]::new);
+ Integer[] asArray = slice.asArray(Integer[]::new);
+ for (int k = start; k < end; k++)
+ assertEquals(array[k], asArray[k - start]);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/boottest/java.base/java/util/stream/SliceSpliteratorTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Spliterator;
+
+import static java.util.stream.Collectors.toList;
+import static org.testng.Assert.assertEquals;
+
+/**
+ * @bug 8012987
+ */
+@Test
+public class SliceSpliteratorTest extends LoggingTestCase {
+
+ static class UnorderedContentAsserter<T> implements SpliteratorTestHelper.ContentAsserter<T> {
+ Collection<T> source;
+
+ UnorderedContentAsserter(Collection<T> source) {
+ this.source = source;
+ }
+
+ @Override
+ public void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered) {
+ if (isOrdered) {
+ assertEquals(actual, expected);
+ }
+ else {
+ assertEquals(actual.size(), expected.size());
+ assertTrue(source.containsAll(actual));
+ }
+ }
+ }
+
+ interface SliceTester {
+ void test(int size, int skip, int limit);
+ }
+
+ @DataProvider(name = "sliceSpliteratorDataProvider")
+ public static Object[][] sliceSpliteratorDataProvider() {
+ List<Object[]> data = new ArrayList<>();
+
+ // SIZED/SUBSIZED slice spliterator
+
+ {
+ SliceTester r = (size, skip, limit) -> {
+ final Collection<Integer> source = IntStream.range(0, size).boxed().collect(toList());
+
+ SpliteratorTestHelper.testSpliterator(() -> {
+ Spliterator<Integer> s = Arrays.spliterator(source.stream().toArray(Integer[]::new));
+
+ return new StreamSpliterators.SliceSpliterator.OfRef<>(s, skip, limit);
+ });
+ };
+ data.add(new Object[]{"StreamSpliterators.SliceSpliterator.OfRef", r});
+ }
+
+ {
+ SliceTester r = (size, skip, limit) -> {
+ final Collection<Integer> source = IntStream.range(0, size).boxed().collect(toList());
+
+ SpliteratorTestHelper.testIntSpliterator(() -> {
+ Spliterator.OfInt s = Arrays.spliterator(source.stream().mapToInt(i->i).toArray());
+
+ return new StreamSpliterators.SliceSpliterator.OfInt(s, skip, limit);
+ });
+ };
+ data.add(new Object[]{"StreamSpliterators.SliceSpliterator.OfInt", r});
+ }
+
+ {
+ SliceTester r = (size, skip, limit) -> {
+ final Collection<Long> source = LongStream.range(0, size).boxed().collect(toList());
+
+ SpliteratorTestHelper.testLongSpliterator(() -> {
+ Spliterator.OfLong s = Arrays.spliterator(source.stream().mapToLong(i->i).toArray());
+
+ return new StreamSpliterators.SliceSpliterator.OfLong(s, skip, limit);
+ });
+ };
+ data.add(new Object[]{"StreamSpliterators.SliceSpliterator.OfLong", r});
+ }
+
+ {
+ SliceTester r = (size, skip, limit) -> {
+ final Collection<Double> source = LongStream.range(0, size).asDoubleStream().boxed().collect(toList());
+
+ SpliteratorTestHelper.testDoubleSpliterator(() -> {
+ Spliterator.OfDouble s = Arrays.spliterator(source.stream().mapToDouble(i->i).toArray());
+
+ return new StreamSpliterators.SliceSpliterator.OfDouble(s, skip, limit);
+ });
+ };
+ data.add(new Object[]{"StreamSpliterators.SliceSpliterator.OfLong", r});
+ }
+
+
+ // Unordered slice spliterator
+
+ {
+ SliceTester r = (size, skip, limit) -> {
+ final Collection<Integer> source = IntStream.range(0, size).boxed().collect(toList());
+ final UnorderedContentAsserter<Integer> uca = new UnorderedContentAsserter<>(source);
+
+ SpliteratorTestHelper.testSpliterator(() -> {
+ Spliterator<Integer> s = Arrays.spliterator(source.stream().toArray(Integer[]::new));
+
+ return new StreamSpliterators.UnorderedSliceSpliterator.OfRef<>(s, skip, limit);
+ }, uca);
+ };
+ data.add(new Object[]{"StreamSpliterators.UnorderedSliceSpliterator.OfRef", r});
+ }
+
+ {
+ SliceTester r = (size, skip, limit) -> {
+ final Collection<Integer> source = IntStream.range(0, size).boxed().collect(toList());
+ final UnorderedContentAsserter<Integer> uca = new UnorderedContentAsserter<>(source);
+
+ SpliteratorTestHelper.testIntSpliterator(() -> {
+ Spliterator.OfInt s = Arrays.spliterator(source.stream().mapToInt(i->i).toArray());
+
+ return new StreamSpliterators.UnorderedSliceSpliterator.OfInt(s, skip, limit);
+ }, uca);
+ };
+ data.add(new Object[]{"StreamSpliterators.UnorderedSliceSpliterator.OfInt", r});
+ }
+
+ {
+ SliceTester r = (size, skip, limit) -> {
+ final Collection<Long> source = LongStream.range(0, size).boxed().collect(toList());
+ final UnorderedContentAsserter<Long> uca = new UnorderedContentAsserter<>(source);
+
+ SpliteratorTestHelper.testLongSpliterator(() -> {
+ Spliterator.OfLong s = Arrays.spliterator(source.stream().mapToLong(i->i).toArray());
+
+ return new StreamSpliterators.UnorderedSliceSpliterator.OfLong(s, skip, limit);
+ }, uca);
+ };
+ data.add(new Object[]{"StreamSpliterators.UnorderedSliceSpliterator.OfLong", r});
+ }
+
+ {
+ SliceTester r = (size, skip, limit) -> {
+ final Collection<Double> source = LongStream.range(0, size).asDoubleStream().boxed().collect(toList());
+ final UnorderedContentAsserter<Double> uca = new UnorderedContentAsserter<>(source);
+
+ SpliteratorTestHelper.testDoubleSpliterator(() -> {
+ Spliterator.OfDouble s = Arrays.spliterator(LongStream.range(0, SIZE).asDoubleStream().toArray());
+
+ return new StreamSpliterators.UnorderedSliceSpliterator.OfDouble(s, skip, limit);
+ }, uca);
+ };
+ data.add(new Object[]{"StreamSpliterators.UnorderedSliceSpliterator.OfLong", r});
+ }
+
+ return data.toArray(new Object[0][]);
+ }
+
+ static final int SIZE = 256;
+
+ static final int STEP = 32;
+
+ @Test(dataProvider = "sliceSpliteratorDataProvider")
+ public void testSliceSpliterator(String description, SliceTester r) {
+ setContext("size", SIZE);
+ for (int skip = 0; skip < SIZE; skip += STEP) {
+ setContext("skip", skip);
+ for (int limit = 0; limit < SIZE; limit += STEP) {
+ setContext("limit", skip);
+ r.test(SIZE, skip, limit);
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/boottest/java.base/java/util/stream/SpinedBufferTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.*;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+@Test
+public class SpinedBufferTest {
+
+ // Create sizes around the boundary of spines
+ static List<Integer> sizes;
+ static {
+ try {
+ sizes = IntStream.range(0, 15)
+ .map(i -> 1 << i)
+ .flatMap(i -> Arrays.stream(new int[] { i-2, i-1, i, i+1, i+2 }))
+ .filter(i -> i >= 0)
+ .boxed()
+ .distinct()
+ .collect(Collectors.toList());
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static final int TEST_SIZE = 5000;
+
+ // SpinedBuffer
+
+ @DataProvider(name = "SpinedBuffer")
+ public Object[][] createSpinedBuffer() {
+ List<Object[]> params = new ArrayList<>();
+
+ for (int size : sizes) {
+ int[] array = IntStream.range(0, size).toArray();
+
+ SpinedBuffer<Integer> sb = new SpinedBuffer<>();
+ Arrays.stream(array).boxed().forEach(sb);
+ params.add(new Object[]{array, sb});
+
+ sb = new SpinedBuffer<>(size / 2);
+ Arrays.stream(array).boxed().forEach(sb);
+ params.add(new Object[]{array, sb});
+
+ sb = new SpinedBuffer<>(size);
+ Arrays.stream(array).boxed().forEach(sb);
+ params.add(new Object[]{array, sb});
+
+ sb = new SpinedBuffer<>(size * 2);
+ Arrays.stream(array).boxed().forEach(sb);
+ params.add(new Object[]{array, sb});
+ }
+
+ return params.toArray(new Object[0][]);
+ }
+
+ @Test(dataProvider = "SpinedBuffer")
+ public void testSpliterator(int[] array, SpinedBuffer<Integer> sb) {
+ assertEquals(sb.count(), array.length);
+ assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
+
+ SpliteratorTestHelper.testSpliterator(sb::spliterator);
+ }
+
+ @Test(dataProvider = "SpinedBuffer", groups = { "serialization-hostile" })
+ public void testLastSplit(int[] array, SpinedBuffer<Integer> sb) {
+ Spliterator<Integer> spliterator = sb.spliterator();
+ Spliterator<Integer> split = spliterator.trySplit();
+ long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
+ long lastSplitSize = spliterator.getExactSizeIfKnown();
+ splitSizes += lastSplitSize;
+
+ assertEquals(splitSizes, array.length);
+
+ List<Integer> contentOfLastSplit = new ArrayList<>();
+ spliterator.forEachRemaining(contentOfLastSplit::add);
+
+ assertEquals(contentOfLastSplit.size(), lastSplitSize);
+
+ List<Integer> end = Arrays.stream(array)
+ .boxed()
+ .skip(array.length - lastSplitSize)
+ .collect(Collectors.toList());
+ assertEquals(contentOfLastSplit, end);
+ }
+
+ @Test(groups = { "serialization-hostile" })
+ public void testSpinedBuffer() {
+ List<Integer> list1 = new ArrayList<>();
+ List<Integer> list2 = new ArrayList<>();
+ SpinedBuffer<Integer> sb = new SpinedBuffer<>();
+ for (int i = 0; i < TEST_SIZE; i++) {
+ list1.add(i);
+ sb.accept(i);
+ }
+ Iterator<Integer> it = sb.iterator();
+ for (int i = 0; i < TEST_SIZE; i++)
+ list2.add(it.next());
+ assertFalse(it.hasNext());
+ assertEquals(list1, list2);
+
+ for (int i = 0; i < TEST_SIZE; i++)
+ assertEquals(sb.get(i), (Integer) i, Integer.toString(i));
+
+ list2.clear();
+ sb.forEach(list2::add);
+ assertEquals(list1, list2);
+ Integer[] array = sb.asArray(LambdaTestHelpers.integerArrayGenerator);
+ list2.clear();
+ for (Integer i : array)
+ list2.add(i);
+ assertEquals(list1, list2);
+ }
+
+ // IntSpinedBuffer
+
+ @DataProvider(name = "IntSpinedBuffer")
+ public Object[][] createIntSpinedBuffer() {
+ List<Object[]> params = new ArrayList<>();
+
+ for (int size : sizes) {
+ int[] array = IntStream.range(0, size).toArray();
+ SpinedBuffer.OfInt sb = new SpinedBuffer.OfInt();
+ Arrays.stream(array).forEach(sb);
+
+ params.add(new Object[]{array, sb});
+ }
+
+ return params.toArray(new Object[0][]);
+ }
+
+ @Test(dataProvider = "IntSpinedBuffer")
+ public void testIntSpliterator(int[] array, SpinedBuffer.OfInt sb) {
+ assertEquals(sb.count(), array.length);
+ assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
+
+ SpliteratorTestHelper.testIntSpliterator(sb::spliterator);
+ }
+
+ @Test(dataProvider = "IntSpinedBuffer", groups = { "serialization-hostile" })
+ public void testIntLastSplit(int[] array, SpinedBuffer.OfInt sb) {
+ Spliterator.OfInt spliterator = sb.spliterator();
+ Spliterator.OfInt split = spliterator.trySplit();
+ long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
+ long lastSplitSize = spliterator.getExactSizeIfKnown();
+ splitSizes += lastSplitSize;
+
+ assertEquals(splitSizes, array.length);
+
+ List<Integer> contentOfLastSplit = new ArrayList<>();
+ spliterator.forEachRemaining((IntConsumer) contentOfLastSplit::add);
+
+ assertEquals(contentOfLastSplit.size(), lastSplitSize);
+
+ List<Integer> end = Arrays.stream(array)
+ .boxed()
+ .skip(array.length - lastSplitSize)
+ .collect(Collectors.toList());
+ assertEquals(contentOfLastSplit, end);
+ }
+
+ @Test(groups = { "serialization-hostile" })
+ public void testIntSpinedBuffer() {
+ List<Integer> list1 = new ArrayList<>();
+ List<Integer> list2 = new ArrayList<>();
+ SpinedBuffer.OfInt sb = new SpinedBuffer.OfInt();
+ for (int i = 0; i < TEST_SIZE; i++) {
+ list1.add(i);
+ sb.accept(i);
+ }
+ PrimitiveIterator.OfInt it = sb.iterator();
+ for (int i = 0; i < TEST_SIZE; i++)
+ list2.add(it.nextInt());
+ assertFalse(it.hasNext());
+ assertEquals(list1, list2);
+
+ for (int i = 0; i < TEST_SIZE; i++)
+ assertEquals(sb.get(i), i, Integer.toString(i));
+
+ list2.clear();
+ sb.forEach((int i) -> list2.add(i));
+ assertEquals(list1, list2);
+ int[] array = sb.asPrimitiveArray();
+ list2.clear();
+ for (int i : array)
+ list2.add(i);
+ assertEquals(list1, list2);
+ }
+
+ // LongSpinedBuffer
+
+ @DataProvider(name = "LongSpinedBuffer")
+ public Object[][] createLongSpinedBuffer() {
+ List<Object[]> params = new ArrayList<>();
+
+ for (int size : sizes) {
+ long[] array = LongStream.range(0, size).toArray();
+ SpinedBuffer.OfLong sb = new SpinedBuffer.OfLong();
+ Arrays.stream(array).forEach(sb);
+
+ params.add(new Object[]{array, sb});
+ }
+
+ return params.toArray(new Object[0][]);
+ }
+
+ @Test(dataProvider = "LongSpinedBuffer")
+ public void testLongSpliterator(long[] array, SpinedBuffer.OfLong sb) {
+ assertEquals(sb.count(), array.length);
+ assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
+
+ SpliteratorTestHelper.testLongSpliterator(sb::spliterator);
+ }
+
+ @Test(dataProvider = "LongSpinedBuffer", groups = { "serialization-hostile" })
+ public void testLongLastSplit(long[] array, SpinedBuffer.OfLong sb) {
+ Spliterator.OfLong spliterator = sb.spliterator();
+ Spliterator.OfLong split = spliterator.trySplit();
+ long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
+ long lastSplitSize = spliterator.getExactSizeIfKnown();
+ splitSizes += lastSplitSize;
+
+ assertEquals(splitSizes, array.length);
+
+ List<Long> contentOfLastSplit = new ArrayList<>();
+ spliterator.forEachRemaining((LongConsumer) contentOfLastSplit::add);
+
+ assertEquals(contentOfLastSplit.size(), lastSplitSize);
+
+ List<Long> end = Arrays.stream(array)
+ .boxed()
+ .skip(array.length - lastSplitSize)
+ .collect(Collectors.toList());
+ assertEquals(contentOfLastSplit, end);
+ }
+
+ @Test(groups = { "serialization-hostile" })
+ public void testLongSpinedBuffer() {
+ List<Long> list1 = new ArrayList<>();
+ List<Long> list2 = new ArrayList<>();
+ SpinedBuffer.OfLong sb = new SpinedBuffer.OfLong();
+ for (long i = 0; i < TEST_SIZE; i++) {
+ list1.add(i);
+ sb.accept(i);
+ }
+ PrimitiveIterator.OfLong it = sb.iterator();
+ for (int i = 0; i < TEST_SIZE; i++)
+ list2.add(it.nextLong());
+ assertFalse(it.hasNext());
+ assertEquals(list1, list2);
+
+ for (int i = 0; i < TEST_SIZE; i++)
+ assertEquals(sb.get(i), i, Long.toString(i));
+
+ list2.clear();
+ sb.forEach((long i) -> list2.add(i));
+ assertEquals(list1, list2);
+ long[] array = sb.asPrimitiveArray();
+ list2.clear();
+ for (long i : array)
+ list2.add(i);
+ assertEquals(list1, list2);
+ }
+
+ // DoubleSpinedBuffer
+
+ @DataProvider(name = "DoubleSpinedBuffer")
+ public Object[][] createDoubleSpinedBuffer() {
+ List<Object[]> params = new ArrayList<>();
+
+ for (int size : sizes) {
+ // @@@ replace with double range when implemented
+ double[] array = LongStream.range(0, size).asDoubleStream().toArray();
+ SpinedBuffer.OfDouble sb = new SpinedBuffer.OfDouble();
+ Arrays.stream(array).forEach(sb);
+
+ params.add(new Object[]{array, sb});
+ }
+
+ return params.toArray(new Object[0][]);
+ }
+
+ @Test(dataProvider = "DoubleSpinedBuffer")
+ public void testDoubleSpliterator(double[] array, SpinedBuffer.OfDouble sb) {
+ assertEquals(sb.count(), array.length);
+ assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
+
+ SpliteratorTestHelper.testDoubleSpliterator(sb::spliterator);
+ }
+
+ @Test(dataProvider = "DoubleSpinedBuffer", groups = { "serialization-hostile" })
+ public void testLongLastSplit(double[] array, SpinedBuffer.OfDouble sb) {
+ Spliterator.OfDouble spliterator = sb.spliterator();
+ Spliterator.OfDouble split = spliterator.trySplit();
+ long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
+ long lastSplitSize = spliterator.getExactSizeIfKnown();
+ splitSizes += lastSplitSize;
+
+ assertEquals(splitSizes, array.length);
+
+ List<Double> contentOfLastSplit = new ArrayList<>();
+ spliterator.forEachRemaining((DoubleConsumer) contentOfLastSplit::add);
+
+ assertEquals(contentOfLastSplit.size(), lastSplitSize);
+
+ List<Double> end = Arrays.stream(array)
+ .boxed()
+ .skip(array.length - lastSplitSize)
+ .collect(Collectors.toList());
+ assertEquals(contentOfLastSplit, end);
+ }
+
+ @Test(groups = { "serialization-hostile" })
+ public void testDoubleSpinedBuffer() {
+ List<Double> list1 = new ArrayList<>();
+ List<Double> list2 = new ArrayList<>();
+ SpinedBuffer.OfDouble sb = new SpinedBuffer.OfDouble();
+ for (long i = 0; i < TEST_SIZE; i++) {
+ list1.add((double) i);
+ sb.accept((double) i);
+ }
+ PrimitiveIterator.OfDouble it = sb.iterator();
+ for (int i = 0; i < TEST_SIZE; i++)
+ list2.add(it.nextDouble());
+ assertFalse(it.hasNext());
+ assertEquals(list1, list2);
+
+ for (int i = 0; i < TEST_SIZE; i++)
+ assertEquals(sb.get(i), (double) i, Double.toString(i));
+
+ list2.clear();
+ sb.forEach((double i) -> list2.add(i));
+ assertEquals(list1, list2);
+ double[] array = sb.asPrimitiveArray();
+ list2.clear();
+ for (double i : array)
+ list2.add(i);
+ assertEquals(list1, list2);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/boottest/java.base/java/util/stream/StreamFlagsTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.*;
+import java.util.stream.Stream;
+import java.util.stream.StreamOpFlag;
+import java.util.stream.Streams;
+
+import static java.util.stream.StreamOpFlag.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * StreamFlagsTest
+ *
+ * @author Brian Goetz
+ */
+@Test
+public class StreamFlagsTest {
+ Stream<String> arrayList = new ArrayList<String>().stream();
+ Stream<String> linkedList = new LinkedList<String>().stream();
+ Stream<String> hashSet = new HashSet<String>().stream();
+ Stream<String> treeSet = new TreeSet<String>().stream();
+ Stream<String> linkedHashSet = new LinkedHashSet<String>().stream();
+ Stream<String> repeat = Stream.generate(() -> "");
+
+ Stream<?>[] streams = { arrayList, linkedList, hashSet, treeSet, linkedHashSet, repeat };
+
+ private void assertFlags(int value, EnumSet<StreamOpFlag> setFlags, EnumSet<StreamOpFlag> clearFlags) {
+ for (StreamOpFlag flag : setFlags)
+ assertTrue(flag.isKnown(value));
+ for (StreamOpFlag flag : clearFlags)
+ assertTrue(!flag.isKnown(value));
+ }
+
+ public void testBaseStreams() {
+ Stream<String> arrayList = new ArrayList<String>().stream();
+ Stream<String> linkedList = new LinkedList<String>().stream();
+ Stream<String> hashSet = new HashSet<String>().stream();
+ Stream<String> treeSet = new TreeSet<String>().stream();
+ Stream<String> linkedHashSet = new LinkedHashSet<String>().stream();
+ Stream<String> repeat = Stream.generate(() -> "");
+
+ assertFlags(OpTestCase.getStreamFlags(arrayList),
+ EnumSet.of(ORDERED, SIZED),
+ EnumSet.of(DISTINCT, SORTED, SHORT_CIRCUIT));
+ assertFlags(OpTestCase.getStreamFlags(linkedList),
+ EnumSet.of(ORDERED, SIZED),
+ EnumSet.of(DISTINCT, SORTED, SHORT_CIRCUIT));
+ assertFlags(OpTestCase.getStreamFlags(hashSet),
+ EnumSet.of(SIZED, DISTINCT),
+ EnumSet.of(ORDERED, SORTED, SHORT_CIRCUIT));
+ assertFlags(OpTestCase.getStreamFlags(treeSet),
+ EnumSet.of(ORDERED, SIZED, DISTINCT, SORTED),
+ EnumSet.of(SHORT_CIRCUIT));
+ assertFlags(OpTestCase.getStreamFlags(linkedHashSet),
+ EnumSet.of(ORDERED, DISTINCT, SIZED),
+ EnumSet.of(SORTED, SHORT_CIRCUIT));
+ assertFlags(OpTestCase.getStreamFlags(repeat),
+ EnumSet.noneOf(StreamOpFlag.class),
+ EnumSet.of(DISTINCT, SORTED, SHORT_CIRCUIT));
+ }
+
+ public void testFilter() {
+ for (Stream<?> s : streams) {
+ int baseFlags = OpTestCase.getStreamFlags(s);
+ int filteredFlags = OpTestCase.getStreamFlags(s.filter((Object e) -> true));
+ int expectedFlags = baseFlags & ~SIZED.set();
+
+ assertEquals(filteredFlags, expectedFlags);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/boottest/java.base/java/util/stream/StreamOpFlagsTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.StreamOpFlag.*;
+import static org.testng.Assert.*;
+import static org.testng.Assert.assertEquals;
+
+@Test
+public class StreamOpFlagsTest {
+
+ public void testNullCombine() {
+ int sourceFlags = StreamOpFlag.IS_SIZED;
+
+ assertEquals(sourceFlags, toStreamFlags(combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE)));
+ }
+
+ public void testInitialOpFlagsFromSourceFlags() {
+ List<StreamOpFlag> flags = new ArrayList<>(StreamOpFlagTestHelper.allStreamFlags());
+ for (int i = 0; i < (1 << flags.size()); i++) {
+ int sourceFlags = 0;
+ for (int f = 0; f < flags.size(); f++) {
+ if ((i & (1 << f)) != 0) {
+ sourceFlags |= flags.get(f).set();
+ }
+ }
+
+ int opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+ assertEquals(opsFlags, (~(sourceFlags << 1)) & StreamOpFlag.INITIAL_OPS_VALUE);
+ }
+ }
+
+ public void testSameCombine() {
+ for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+ int sourceFlags = f.set();
+ int opsFlags;
+
+ opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+ opsFlags = combineOpFlags(f.set(), opsFlags);
+ assertEquals(sourceFlags, toStreamFlags(opsFlags));
+ }
+ }
+
+ public void testOpClear() {
+ for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+ // Clear when source not set
+ int sourceFlags = 0;
+ int opsFlags;
+
+ opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+ opsFlags = combineOpFlags(f.clear(), opsFlags);
+ assertEquals(sourceFlags, toStreamFlags(opsFlags));
+
+ // Clear when source set
+ sourceFlags = f.set();
+
+ opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+ opsFlags = combineOpFlags(f.clear(), opsFlags);
+ assertEquals(0, toStreamFlags(opsFlags));
+ }
+ }
+
+ public void testOpInject() {
+ for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+ // Set when source not set
+ int sourceFlags = 0;
+ int opsFlags;
+
+ opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+ opsFlags = combineOpFlags(f.set(), opsFlags);
+ assertEquals(f.set(), toStreamFlags(opsFlags));
+
+ // Set when source set
+ sourceFlags = f.set();
+
+ opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+ opsFlags = combineOpFlags(f.set(), opsFlags);
+ assertEquals(sourceFlags, toStreamFlags(opsFlags));
+ }
+ }
+
+ public void testPairSet() {
+ List<Integer> sourceFlagsList
+ = StreamOpFlagTestHelper.allStreamFlags().stream().map(StreamOpFlag::set).collect(toList());
+ sourceFlagsList.add(0, 0);
+
+ for (int sourceFlags : sourceFlagsList) {
+ for (StreamOpFlag f1 : StreamOpFlagTestHelper.allStreamFlags()) {
+ for (StreamOpFlag f2 : StreamOpFlagTestHelper.allStreamFlags()) {
+ int opsFlags;
+
+ opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+ opsFlags = combineOpFlags(f1.set(), opsFlags);
+ opsFlags = combineOpFlags(f2.set(), opsFlags);
+ assertEquals(sourceFlags | f1.set() | f2.set(), toStreamFlags(opsFlags));
+ }
+ }
+ }
+ }
+
+ public void testPairSetAndClear() {
+ List<Integer> sourceFlagsList
+ = StreamOpFlagTestHelper.allStreamFlags().stream().map(StreamOpFlag::set).collect(toList());
+ sourceFlagsList.add(0, 0);
+
+ for (int sourceFlags : sourceFlagsList) {
+ for (StreamOpFlag f1 : StreamOpFlagTestHelper.allStreamFlags()) {
+ for (StreamOpFlag f2 : StreamOpFlagTestHelper.allStreamFlags()) {
+ int opsFlags;
+
+ opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+ opsFlags = combineOpFlags(f1.set(), opsFlags);
+ opsFlags = combineOpFlags(f2.clear(), opsFlags);
+ if (f1 == f2)
+ assertEquals((f2.set() == sourceFlags) ? 0 : sourceFlags, toStreamFlags(opsFlags));
+ else
+ assertEquals((f2.set() == sourceFlags) ? f1.set() : sourceFlags | f1.set(), toStreamFlags(opsFlags));
+ }
+ }
+ }
+ }
+
+ public void testShortCircuit() {
+ int opsFlags = combineOpFlags(0, StreamOpFlag.INITIAL_OPS_VALUE);
+ assertFalse(StreamOpFlag.SHORT_CIRCUIT.isKnown(opsFlags));
+
+ opsFlags = combineOpFlags(StreamOpFlag.IS_SHORT_CIRCUIT, opsFlags);
+ assertTrue(StreamOpFlag.SHORT_CIRCUIT.isKnown(opsFlags));
+
+ opsFlags = combineOpFlags(0, opsFlags);
+ assertTrue(StreamOpFlag.SHORT_CIRCUIT.isKnown(opsFlags));
+ }
+
+ public void testApplySourceFlags() {
+ int sourceFlags = StreamOpFlag.IS_SIZED | StreamOpFlag.IS_DISTINCT;
+
+ List<Integer> ops = Arrays.asList(StreamOpFlag.NOT_SIZED, StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
+
+ int opsFlags = StreamOpFlag.combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+ for (int opFlags : ops) {
+ opsFlags = combineOpFlags(opFlags, opsFlags);
+ }
+ assertFalse(StreamOpFlag.SIZED.isKnown(opsFlags));
+ assertTrue(StreamOpFlag.SIZED.isCleared(opsFlags));
+ assertFalse(StreamOpFlag.SIZED.isPreserved(opsFlags));
+ assertTrue(StreamOpFlag.DISTINCT.isKnown(opsFlags));
+ assertFalse(StreamOpFlag.DISTINCT.isCleared(opsFlags));
+ assertFalse(StreamOpFlag.DISTINCT.isPreserved(opsFlags));
+ assertTrue(StreamOpFlag.SORTED.isKnown(opsFlags));
+ assertFalse(StreamOpFlag.SORTED.isCleared(opsFlags));
+ assertFalse(StreamOpFlag.SORTED.isPreserved(opsFlags));
+ assertTrue(StreamOpFlag.ORDERED.isKnown(opsFlags));
+ assertFalse(StreamOpFlag.ORDERED.isCleared(opsFlags));
+ assertFalse(StreamOpFlag.ORDERED.isPreserved(opsFlags));
+
+ int streamFlags = toStreamFlags(opsFlags);
+ assertFalse(StreamOpFlag.SIZED.isKnown(streamFlags));
+ assertTrue(StreamOpFlag.DISTINCT.isKnown(streamFlags));
+ assertTrue(StreamOpFlag.SORTED.isKnown(streamFlags));
+ assertTrue(StreamOpFlag.ORDERED.isKnown(streamFlags));
+ }
+
+ public void testSpliteratorMask() {
+ assertSpliteratorMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
+ assertSpliteratorMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+ assertSpliteratorMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
+ assertSpliteratorMask(StreamOpFlag.SORTED.clear(), 0);
+
+ assertSpliteratorMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
+ assertSpliteratorMask(StreamOpFlag.ORDERED.clear(), 0);
+
+ assertSpliteratorMask(StreamOpFlag.SIZED.set(), StreamOpFlag.IS_SIZED);
+ assertSpliteratorMask(StreamOpFlag.SIZED.clear(), 0);
+
+ assertSpliteratorMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
+ assertSpliteratorMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+ }
+
+ private void assertSpliteratorMask(int actual, int expected) {
+ assertEquals(actual & StreamOpFlag.SPLITERATOR_CHARACTERISTICS_MASK, expected);
+ }
+
+ public void testStreamMask() {
+ assertStreamMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
+ assertStreamMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+ assertStreamMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
+ assertStreamMask(StreamOpFlag.SORTED.clear(), 0);
+
+ assertStreamMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
+ assertStreamMask(StreamOpFlag.ORDERED.clear(), 0);
+
+ assertStreamMask(StreamOpFlag.SIZED.set(), StreamOpFlag.IS_SIZED);
+ assertStreamMask(StreamOpFlag.SIZED.clear(), 0);
+
+ assertStreamMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
+ assertStreamMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+ }
+
+ private void assertStreamMask(int actual, int expected) {
+ assertEquals(actual & StreamOpFlag.STREAM_MASK, expected);
+ }
+
+ public void testOpMask() {
+ assertOpMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
+ assertOpMask(StreamOpFlag.DISTINCT.clear(), StreamOpFlag.NOT_DISTINCT);
+
+ assertOpMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
+ assertOpMask(StreamOpFlag.SORTED.clear(), StreamOpFlag.NOT_SORTED);
+
+ assertOpMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
+ assertOpMask(StreamOpFlag.ORDERED.clear(), StreamOpFlag.NOT_ORDERED);
+
+ assertOpMask(StreamOpFlag.SIZED.set(), 0);
+ assertOpMask(StreamOpFlag.SIZED.clear(), StreamOpFlag.NOT_SIZED);
+
+ assertOpMask(StreamOpFlag.SHORT_CIRCUIT.set(), StreamOpFlag.IS_SHORT_CIRCUIT);
+ assertOpMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+ }
+
+ private void assertOpMask(int actual, int expected) {
+ assertEquals(actual & StreamOpFlag.OP_MASK, expected);
+ }
+
+ public void testTerminalOpMask() {
+ assertTerminalOpMask(StreamOpFlag.DISTINCT.set(), 0);
+ assertTerminalOpMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+ assertTerminalOpMask(StreamOpFlag.SORTED.set(), 0);
+ assertTerminalOpMask(StreamOpFlag.SORTED.clear(), 0);
+
+ assertTerminalOpMask(StreamOpFlag.ORDERED.set(), 0);
+ assertTerminalOpMask(StreamOpFlag.ORDERED.clear(), StreamOpFlag.NOT_ORDERED);
+
+ assertTerminalOpMask(StreamOpFlag.SIZED.set(), 0);
+ assertTerminalOpMask(StreamOpFlag.SIZED.clear(), 0);
+
+ assertTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.set(), StreamOpFlag.IS_SHORT_CIRCUIT);
+ assertTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+ }
+
+ private void assertTerminalOpMask(int actual, int expected) {
+ assertEquals(actual & StreamOpFlag.TERMINAL_OP_MASK, expected);
+ }
+
+ public void testUpstreamTerminalOpMask() {
+ assertUpstreamTerminalOpMask(StreamOpFlag.DISTINCT.set(), 0);
+ assertUpstreamTerminalOpMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+ assertUpstreamTerminalOpMask(StreamOpFlag.SORTED.set(), 0);
+ assertUpstreamTerminalOpMask(StreamOpFlag.SORTED.clear(), 0);
+
+ assertUpstreamTerminalOpMask(StreamOpFlag.ORDERED.set(), 0);
+ assertUpstreamTerminalOpMask(StreamOpFlag.ORDERED.clear(), StreamOpFlag.NOT_ORDERED);
+
+ assertUpstreamTerminalOpMask(StreamOpFlag.SIZED.set(), 0);
+ assertUpstreamTerminalOpMask(StreamOpFlag.SIZED.clear(), 0);
+
+ assertUpstreamTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
+ assertUpstreamTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+ }
+
+ private void assertUpstreamTerminalOpMask(int actual, int expected) {
+ assertEquals(actual & StreamOpFlag.UPSTREAM_TERMINAL_OP_MASK, expected);
+ }
+
+ public void testSpliteratorCharacteristics() {
+ assertEquals(Spliterator.DISTINCT, StreamOpFlag.IS_DISTINCT);
+ assertEquals(Spliterator.SORTED, StreamOpFlag.IS_SORTED);
+ assertEquals(Spliterator.ORDERED, StreamOpFlag.IS_ORDERED);
+ assertEquals(Spliterator.SIZED, StreamOpFlag.IS_SIZED);
+
+ List<Integer> others = Arrays.asList(Spliterator.NONNULL, Spliterator.IMMUTABLE,
+ Spliterator.CONCURRENT, Spliterator.SUBSIZED);
+ for (int c : others) {
+ assertNotEquals(c, StreamOpFlag.IS_SHORT_CIRCUIT);
+ }
+ }
+
+ public void testSpliteratorCharacteristicsMask() {
+ assertSpliteratorCharacteristicsMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
+ assertSpliteratorCharacteristicsMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+ assertSpliteratorCharacteristicsMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
+ assertSpliteratorCharacteristicsMask(StreamOpFlag.SORTED.clear(), 0);
+
+ assertSpliteratorCharacteristicsMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
+ assertSpliteratorCharacteristicsMask(StreamOpFlag.ORDERED.clear(), 0);
+
+ assertSpliteratorCharacteristicsMask(StreamOpFlag.SIZED.set(), StreamOpFlag.IS_SIZED);
+ assertSpliteratorCharacteristicsMask(StreamOpFlag.SIZED.clear(), 0);
+
+ assertSpliteratorCharacteristicsMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
+ assertSpliteratorCharacteristicsMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+ }
+
+ private void assertSpliteratorCharacteristicsMask(int actual, int expected) {
+ assertEquals(StreamOpFlag.fromCharacteristics(actual), expected);
+ }
+
+ public void testSpliteratorSorted() {
+ class SortedEmptySpliterator implements Spliterator<Object> {
+ final Comparator<Object> c;
+
+ SortedEmptySpliterator(Comparator<Object> c) {
+ this.c = c;
+ }
+
+ @Override
+ public Spliterator<Object> trySplit() {
+ return null;
+ }
+
+ @Override
+ public boolean tryAdvance(Consumer<? super Object> action) {
+ return false;
+ }
+
+ @Override
+ public long estimateSize() {
+ return Long.MAX_VALUE;
+ }
+
+ @Override
+ public int characteristics() {
+ return Spliterator.SORTED;
+ }
+
+ @Override
+ public Comparator<? super Object> getComparator() {
+ return c;
+ }
+ };
+
+ {
+ int flags = StreamOpFlag.fromCharacteristics(new SortedEmptySpliterator(null));
+ assertEquals(flags, StreamOpFlag.IS_SORTED);
+ }
+
+ {
+ int flags = StreamOpFlag.fromCharacteristics(new SortedEmptySpliterator((a, b) -> 0));
+ assertEquals(flags, 0);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/boottest/java.base/java/util/stream/StreamReuseTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.function.Function;
+
+import static org.testng.Assert.fail;
+
+/**
+ * StreamReuseTest
+ *
+ * @author Brian Goetz
+ */
+@Test
+public class StreamReuseTest {
+
+ private <T, U, E, S extends BaseStream<E, S>, D extends TestData<E, S>> void assertSecondFails(
+ D data,
+ Function<S, T> first,
+ Function<S, U> second,
+ Class<? extends Throwable> exception,
+ String text) {
+ S stream = data.stream();
+ T fr = first.apply(stream);
+ try {
+ U sr = second.apply(stream);
+ fail(text + " (seq)");
+ }
+ catch (Throwable e) {
+ if (exception.isAssignableFrom(e.getClass())) {
+ // Expected
+ }
+ else if (e instanceof Error)
+ throw (Error) e;
+ else if (e instanceof RuntimeException)
+ throw (RuntimeException) e;
+ else
+ throw new AssertionError("Unexpected exception " + e.getClass(), e);
+ }
+
+ stream = data.parallelStream();
+ fr = first.apply(stream);
+ try {
+ U sr = second.apply(stream);
+ fail(text + " (par)");
+ }
+ catch (Throwable e) {
+ if (exception.isAssignableFrom(e.getClass())) {
+ // Expected
+ }
+ else if (e instanceof Error)
+ throw (Error) e;
+ else if (e instanceof RuntimeException)
+ throw (RuntimeException) e;
+ else
+ throw new AssertionError("Unexpected exception " + e.getClass(), e);
+ }
+ }
+
+ // Stream
+
+ @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+ public void testTwoStreams(String name, TestData<Integer, Stream<Integer>> data) {
+ assertSecondFails(data,
+ (Stream<Integer> s) -> s.map(i -> i), (Stream<Integer> s) -> s.map(i -> i),
+ IllegalStateException.class,
+ "Stream map / map succeeded erroneously");
+ assertSecondFails(data,
+ Stream::distinct, (Stream<Integer> s) -> s.map(i -> i),
+ IllegalStateException.class,
+ "Stream distinct / map succeeded erroneously");
+ assertSecondFails(data,
+ (Stream<Integer> s) -> s.map(i -> i), Stream::distinct,
+ IllegalStateException.class,
+ "Stream map / distinct succeeded erroneously");
+ assertSecondFails(data,
+ Stream::distinct, Stream::distinct,
+ IllegalStateException.class,
+ "Stream distinct / distinct succeeded erroneously");
+ }
+
+ @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+ public void testTwoTerminals(String name, TestData<Integer, Stream<Integer>> data) {
+ assertSecondFails(data,
+ Stream::findFirst, Stream::findFirst,
+ IllegalStateException.class,
+ "Stream findFirst / findFirst succeeded erroneously");
+ }
+
+ @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+ public void testTerminalStream(String name, TestData<Integer, Stream<Integer>> data) {
+ assertSecondFails(data,
+ Stream::findFirst, (Stream<Integer> s) -> s.map(i -> i),
+ IllegalStateException.class,
+ "Stream findFirst / map succeeded erroneously");
+ assertSecondFails(data,
+ (Stream<Integer> s) -> s.map(i -> i), Stream::findFirst,
+ IllegalStateException.class,
+ "Stream map / findFirst succeeded erroneously");
+ assertSecondFails(data,
+ Stream::findFirst, Stream::distinct,
+ IllegalStateException.class,
+ "Stream findFirst / distinct succeeded erroneously");
+ assertSecondFails(data,
+ Stream::distinct, Stream::findFirst,
+ IllegalStateException.class,
+ "Stream distinct / findFirst succeeded erroneously");
+ }
+
+ @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+ public void testTwoIterators(String name, TestData<Integer, Stream<Integer>> data) {
+ assertSecondFails(data,
+ Stream::iterator, Stream::iterator,
+ IllegalStateException.class,
+ "Stream iterator / iterator succeeded erroneously");
+ }
+
+ @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+ public void testTerminalIterator(String name, TestData<Integer, Stream<Integer>> data) {
+ assertSecondFails(data,
+ Stream::iterator, Stream::findFirst,
+ IllegalStateException.class,
+ "Stream iterator / findFirst succeeded erroneously");
+ assertSecondFails(data,
+ Stream::findFirst, Stream::iterator,
+ IllegalStateException.class,
+ "Stream findFirst / iterator succeeded erroneously");
+ }
+
+ @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+ public void testStreamIterator(String name, TestData<Integer, Stream<Integer>> data) {
+ assertSecondFails(data,
+ Stream::iterator, (Stream<Integer> s) -> s.map(i -> i),
+ IllegalStateException.class,
+ "Stream iterator / map succeeded erroneously");
+ assertSecondFails(data,
+ (Stream<Integer> s) -> s.map(i -> i), Stream::iterator,
+ IllegalStateException.class,
+ "Stream map / iterator succeeded erroneously");
+ assertSecondFails(data,
+ Stream::iterator, Stream::distinct,
+ IllegalStateException.class,
+ "Stream iterator / distinct succeeded erroneously");
+ assertSecondFails(data,
+ Stream::distinct, Stream::iterator,
+ IllegalStateException.class,
+ "Stream distinct / iterator succeeded erroneously");
+ }
+
+ // IntStream
+
+ @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+ public void testTwoStreams(String name, TestData.OfInt data) {
+ assertSecondFails(data,
+ (IntStream s) -> s.mapToObj(i -> i), (IntStream s) -> s.mapToObj(i -> i),
+ IllegalStateException.class,
+ "IntStream map / map succeeded erroneously");
+ assertSecondFails(data,
+ IntStream::distinct, (IntStream s) -> s.mapToObj(i -> i),
+ IllegalStateException.class,
+ "IntStream distinct / map succeeded erroneously");
+ assertSecondFails(data,
+ (IntStream s) -> s.mapToObj(i -> i), IntStream::distinct,
+ IllegalStateException.class,
+ "IntStream map / distinct succeeded erroneously");
+ assertSecondFails(data,
+ IntStream::distinct, IntStream::distinct,
+ IllegalStateException.class,
+ "IntStream distinct / distinct succeeded erroneously");
+ }
+
+ @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+ public void testTwoTerminals(String name, TestData.OfInt data) {
+ assertSecondFails(data,
+ IntStream::sum, IntStream::sum,
+ IllegalStateException.class,
+ "IntStream sum / sum succeeded erroneously");
+ }
+
+ @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+ public void testTerminalStream(String name, TestData.OfInt data) {
+ assertSecondFails(data,
+ IntStream::sum, (IntStream s) -> s.mapToObj(i -> i),
+ IllegalStateException.class,
+ "IntStream sum / map succeeded erroneously");
+ assertSecondFails(data,
+ (IntStream s) -> s.mapToObj(i -> i), IntStream::sum,
+ IllegalStateException.class,
+ "IntStream map / sum succeeded erroneously");
+ assertSecondFails(data,
+ IntStream::sum, IntStream::distinct,
+ IllegalStateException.class,
+ "IntStream sum / distinct succeeded erroneously");
+ assertSecondFails(data,
+ IntStream::distinct, IntStream::sum,
+ IllegalStateException.class,
+ "IntStream distinct / sum succeeded erroneously");
+ }
+
+ @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+ public void testTwoIterators(String name, TestData.OfInt data) {
+ assertSecondFails(data,
+ IntStream::iterator, IntStream::iterator,
+ IllegalStateException.class,
+ "IntStream iterator / iterator succeeded erroneously");
+ }
+
+ @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+ public void testTerminalIterator(String name, TestData.OfInt data) {
+ assertSecondFails(data,
+ IntStream::iterator, IntStream::sum,
+ IllegalStateException.class,
+ "IntStream iterator / sum succeeded erroneously");
+ assertSecondFails(data,
+ IntStream::sum, IntStream::iterator,
+ IllegalStateException.class,
+ "Stream sum / iterator succeeded erroneously");
+ }
+
+ @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+ public void testStreamIterator(String name, TestData.OfInt data) {
+ assertSecondFails(data,
+ IntStream::iterator, (IntStream s) -> s.mapToObj(i -> i),
+ IllegalStateException.class,
+ "IntStream iterator / map succeeded erroneously");
+ assertSecondFails(data,
+ (IntStream s) -> s.mapToObj(i -> i), IntStream::iterator,
+ IllegalStateException.class,
+ "IntStream map / iterator succeeded erroneously");
+ assertSecondFails(data,
+ IntStream::iterator, IntStream::distinct,
+ IllegalStateException.class,
+ "IntStream iterator / distinct succeeded erroneously");
+ assertSecondFails(data,
+ IntStream::distinct, IntStream::iterator,
+ IllegalStateException.class,
+ "IntStream distinct / iterator succeeded erroneously");
+ }
+
+ // LongStream
+
+ @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+ public void testTwoStreams(String name, TestData.OfLong data) {
+ assertSecondFails(data,
+ (LongStream s) -> s.mapToObj(i -> i), (LongStream s) -> s.mapToObj(i -> i),
+ IllegalStateException.class,
+ "LongStream map / map succeeded erroneously");
+ assertSecondFails(data,
+ LongStream::distinct, (LongStream s) -> s.mapToObj(i -> i),
+ IllegalStateException.class,
+ "LongStream distinct / map succeeded erroneously");
+ assertSecondFails(data,
+ (LongStream s) -> s.mapToObj(i -> i), LongStream::distinct,
+ IllegalStateException.class,
+ "LongStream map / distinct succeeded erroneously");
+ assertSecondFails(data,
+ LongStream::distinct, LongStream::distinct,
+ IllegalStateException.class,
+ "LongStream distinct / distinct succeeded erroneously");
+ }
+
+ @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+ public void testTwoTerminals(String name, TestData.OfLong data) {
+ assertSecondFails(data,
+ LongStream::sum, LongStream::sum,
+ IllegalStateException.class,
+ "LongStream sum / sum succeeded erroneously");
+ }
+
+ @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+ public void testTerminalStream(String name, TestData.OfLong data) {
+ assertSecondFails(data,
+ LongStream::sum, (LongStream s) -> s.mapToObj(i -> i),
+ IllegalStateException.class,
+ "LongStream sum / map succeeded erroneously");
+ assertSecondFails(data,
+ (LongStream s) -> s.mapToObj(i -> i), LongStream::sum,
+ IllegalStateException.class,
+ "LongStream map / sum succeeded erroneously");
+ assertSecondFails(data,
+ LongStream::sum, LongStream::distinct,
+ IllegalStateException.class,
+ "LongStream sum / distinct succeeded erroneously");
+ assertSecondFails(data,
+ LongStream::distinct, LongStream::sum,
+ IllegalStateException.class,
+ "LongStream distinct / sum succeeded erroneously");
+ }
+
+ @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+ public void testTwoIterators(String name, TestData.OfLong data) {
+ assertSecondFails(data,
+ LongStream::iterator, LongStream::iterator,
+ IllegalStateException.class,
+ "LongStream iterator / iterator succeeded erroneously");
+ }
+
+ @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+ public void testTerminalIterator(String name, TestData.OfLong data) {
+ assertSecondFails(data,
+ LongStream::iterator, LongStream::sum,
+ IllegalStateException.class,
+ "LongStream iterator / sum succeeded erroneously");
+ assertSecondFails(data,
+ LongStream::sum, LongStream::iterator,
+ IllegalStateException.class,
+ "Stream sum / iterator succeeded erroneously");
+ }
+
+ @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+ public void testStreamIterator(String name, TestData.OfLong data) {
+ assertSecondFails(data,
+ LongStream::iterator, (LongStream s) -> s.mapToObj(i -> i),
+ IllegalStateException.class,
+ "LongStream iterator / map succeeded erroneously");
+ assertSecondFails(data,
+ (LongStream s) -> s.mapToObj(i -> i), LongStream::iterator,
+ IllegalStateException.class,
+ "LongStream map / iterator succeeded erroneously");
+ assertSecondFails(data,
+ LongStream::iterator, LongStream::distinct,
+ IllegalStateException.class,
+ "LongStream iterator / distinct succeeded erroneously");
+ assertSecondFails(data,
+ LongStream::distinct, LongStream::iterator,
+ IllegalStateException.class,
+ "LongStream distinct / iterator succeeded erroneously");
+ }
+
+ // DoubleStream
+
+ @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+ public void testTwoStreams(String name, TestData.OfDouble data) {
+ assertSecondFails(data,
+ (DoubleStream s) -> s.mapToObj(i -> i), (DoubleStream s) -> s.mapToObj(i -> i),
+ IllegalStateException.class,
+ "DoubleStream map / map succeeded erroneously");
+ assertSecondFails(data,
+ DoubleStream::distinct, (DoubleStream s) -> s.mapToObj(i -> i),
+ IllegalStateException.class,
+ "DoubleStream distinct / map succeeded erroneously");
+ assertSecondFails(data,
+ (DoubleStream s) -> s.mapToObj(i -> i), DoubleStream::distinct,
+ IllegalStateException.class,
+ "DoubleStream map / distinct succeeded erroneously");
+ assertSecondFails(data,
+ DoubleStream::distinct, DoubleStream::distinct,
+ IllegalStateException.class,
+ "DoubleStream distinct / distinct succeeded erroneously");
+ }
+
+ @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+ public void testTwoTerminals(String name, TestData.OfDouble data) {
+ assertSecondFails(data,
+ DoubleStream::sum, DoubleStream::sum,
+ IllegalStateException.class,
+ "DoubleStream sum / sum succeeded erroneously");
+ }
+
+ @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+ public void testTerminalStream(String name, TestData.OfDouble data) {
+ assertSecondFails(data,
+ DoubleStream::sum, (DoubleStream s) -> s.mapToObj(i -> i),
+ IllegalStateException.class,
+ "DoubleStream sum / map succeeded erroneously");
+ assertSecondFails(data,
+ (DoubleStream s) -> s.mapToObj(i -> i), DoubleStream::sum,
+ IllegalStateException.class,
+ "DoubleStream map / sum succeeded erroneously");
+ assertSecondFails(data,
+ DoubleStream::sum, DoubleStream::distinct,
+ IllegalStateException.class,
+ "DoubleStream sum / distinct succeeded erroneously");
+ assertSecondFails(data,
+ DoubleStream::distinct, DoubleStream::sum,
+ IllegalStateException.class,
+ "DoubleStream distinct / sum succeeded erroneously");
+ }
+
+ @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+ public void testTwoIterators(String name, TestData.OfDouble data) {
+ assertSecondFails(data,
+ DoubleStream::iterator, DoubleStream::iterator,
+ IllegalStateException.class,
+ "DoubleStream iterator / iterator succeeded erroneously");
+ }
+
+ @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+ public void testTerminalIterator(String name, TestData.OfDouble data) {
+ assertSecondFails(data,
+ DoubleStream::iterator, DoubleStream::sum,
+ IllegalStateException.class,
+ "DoubleStream iterator / sum succeeded erroneously");
+ assertSecondFails(data,
+ DoubleStream::sum, DoubleStream::iterator,
+ IllegalStateException.class,
+ "Stream sum / iterator succeeded erroneously");
+ }
+
+ @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+ public void testStreamIterator(String name, TestData.OfDouble data) {
+ assertSecondFails(data,
+ DoubleStream::iterator, (DoubleStream s) -> s.mapToObj(i -> i),
+ IllegalStateException.class,
+ "DoubleStream iterator / map succeeded erroneously");
+ assertSecondFails(data,
+ (DoubleStream s) -> s.mapToObj(i -> i), DoubleStream::iterator,
+ IllegalStateException.class,
+ "DoubleStream map / iterator succeeded erroneously");
+ assertSecondFails(data,
+ DoubleStream::iterator, DoubleStream::distinct,
+ IllegalStateException.class,
+ "DoubleStream iterator / distinct succeeded erroneously");
+ assertSecondFails(data,
+ DoubleStream::distinct, DoubleStream::iterator,
+ IllegalStateException.class,
+ "DoubleStream distinct / iterator succeeded erroneously");
+ }
+}
--- a/jdk/test/java/util/stream/boottest/java/util/stream/DoubleNodeTest.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,179 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.PrimitiveIterator;
-import java.util.Spliterators;
-import java.util.function.Function;
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-@Test
-public class DoubleNodeTest extends OpTestCase {
-
- @DataProvider(name = "nodes")
- public Object[][] createSizes() {
- List<Object[]> params = new ArrayList<>();
-
- for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
- double[] array = new double[size];
- for (int i = 0; i < array.length; i++) {
- array[i] = i;
- }
-
- List<Node<Double>> nodes = new ArrayList<>();
-
- nodes.add(Nodes.node(array));
- nodes.add(degenerateTree(Spliterators.iterator(Arrays.spliterator(array))));
- nodes.add(tree(toList(array), l -> Nodes.node(toDoubleArray(l))));
- nodes.add(fill(array, Nodes.doubleBuilder(array.length)));
- nodes.add(fill(array, Nodes.doubleBuilder()));
-
- for (Node<Double> node : nodes) {
- params.add(new Object[]{array, node});
- }
-
- }
-
- return params.toArray(new Object[0][]);
- }
-
- private static void assertEqualsListDoubleArray(List<Double> list, double[] array) {
- assertEquals(list.size(), array.length);
- for (int i = 0; i < array.length; i++)
- assertEquals(array[i], list.get(i));
- }
-
- private List<Double> toList(double[] a) {
- List<Double> l = new ArrayList<>();
- for (double i : a) {
- l.add(i);
- }
-
- return l;
- }
-
- private double[] toDoubleArray(List<Double> l) {
- double[] a = new double[l.size()];
-
- int i = 0;
- for (Double e : l) {
- a[i++] = e;
- }
- return a;
- }
-
- private Node.OfDouble fill(double[] array, Node.Builder.OfDouble nb) {
- nb.begin(array.length);
- for (double i : array)
- nb.accept(i);
- nb.end();
- return nb.build();
- }
-
- private Node.OfDouble degenerateTree(PrimitiveIterator.OfDouble it) {
- if (!it.hasNext()) {
- return Nodes.node(new double[0]);
- }
-
- double i = it.nextDouble();
- if (it.hasNext()) {
- return new Nodes.ConcNode.OfDouble(Nodes.node(new double[] {i}), degenerateTree(it));
- }
- else {
- return Nodes.node(new double[] {i});
- }
- }
-
- private Node.OfDouble tree(List<Double> l, Function<List<Double>, Node.OfDouble> m) {
- if (l.size() < 3) {
- return m.apply(l);
- }
- else {
- return new Nodes.ConcNode.OfDouble(
- tree(l.subList(0, l.size() / 2), m),
- tree(l.subList(l.size() / 2, l.size()), m));
- }
- }
-
- @Test(dataProvider = "nodes")
- public void testAsArray(double[] array, Node.OfDouble n) {
- assertEquals(n.asPrimitiveArray(), array);
- }
-
- @Test(dataProvider = "nodes")
- public void testFlattenAsArray(double[] array, Node.OfDouble n) {
- assertEquals(Nodes.flattenDouble(n).asPrimitiveArray(), array);
- }
-
- @Test(dataProvider = "nodes")
- public void testCopyTo(double[] array, Node.OfDouble n) {
- double[] copy = new double[(int) n.count()];
- n.copyInto(copy, 0);
-
- assertEquals(copy, array);
- }
-
- @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
- public void testForEach(double[] array, Node.OfDouble n) {
- List<Double> l = new ArrayList<>((int) n.count());
- n.forEach((double e) -> {
- l.add(e);
- });
-
- assertEqualsListDoubleArray(l, array);
- }
-
- @Test(dataProvider = "nodes")
- public void testStreams(double[] array, Node.OfDouble n) {
- TestData.OfDouble data = TestData.Factory.ofNode("Node", n);
-
- exerciseOps(data, s -> s);
-
- exerciseTerminalOps(data, s -> s.toArray());
- }
-
- @Test(dataProvider = "nodes", groups={ "serialization-hostile" })
- // throws SOE on serialization of DoubleConcNode[size=1000]
- public void testSpliterator(double[] array, Node.OfDouble n) {
- SpliteratorTestHelper.testDoubleSpliterator(n::spliterator);
- }
-
- @Test(dataProvider = "nodes")
- public void testTruncate(double[] array, Node.OfDouble n) {
- int[] nums = new int[] { 0, 1, array.length / 2, array.length - 1, array.length };
- for (int start : nums)
- for (int end : nums) {
- if (start < 0 || end < 0 || end < start || end > array.length)
- continue;
- Node.OfDouble slice = n.truncate(start, end, Double[]::new);
- double[] asArray = slice.asPrimitiveArray();
- for (int k = start; k < end; k++)
- assertEquals(array[k], asArray[k - start]);
- }
- }
-}
--- a/jdk/test/java/util/stream/boottest/java/util/stream/FlagOpTest.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,283 +0,0 @@
-/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.function.Supplier;
-
-import static java.util.stream.LambdaTestHelpers.countTo;
-
-@Test
-public class FlagOpTest extends OpTestCase {
-
- @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
- public void testFlagsPassThrough(String name, TestData<Integer, Stream<Integer>> data) {
-
- @SuppressWarnings({"unchecked", "rawtypes"})
- TestFlagPassThroughOp<Integer>[] ops = new TestFlagPassThroughOp[3];
- ops[0] = new TestFlagPassThroughOp<>();
- ops[1] = new TestFlagPassThroughOp<>();
- ops[2] = new TestFlagPassThroughOp<>();
-
- ops[0].set(null, ops[1]);
- ops[1].set(ops[0], ops[2]);
- ops[2].set(ops[1], null);
-
- withData(data).ops(ops).exercise();
- }
-
- static class TestFlagPassThroughOp<T> extends FlagDeclaringOp<T> {
- TestFlagPassThroughOp<T> upstream;
- TestFlagPassThroughOp<T> downstream;
-
- TestFlagPassThroughOp() {
- super(0);
- }
-
- void set(TestFlagPassThroughOp<T> upstream, TestFlagPassThroughOp<T> downstream) {
- this.upstream = upstream;
- this.downstream = downstream;
- }
-
- int wrapFlags;
-
- @Override
- @SuppressWarnings({"unchecked", "rawtypes"})
- public Sink<T> opWrapSink(int flags, boolean parallel, Sink sink) {
- this.wrapFlags = flags;
-
- if (downstream != null) {
- assertTrue(flags == downstream.wrapFlags);
- }
-
- return sink;
- }
- }
-
- public void testFlagsClearAllSet() {
- int clearAllFlags = 0;
- for (StreamOpFlag f : EnumSet.allOf(StreamOpFlag.class)) {
- if (f.isStreamFlag()) {
- clearAllFlags |= f.clear();
- }
- }
-
- EnumSet<StreamOpFlag> known = EnumSet.noneOf(StreamOpFlag.class);
- EnumSet<StreamOpFlag> notKnown = StreamOpFlagTestHelper.allStreamFlags();
-
- List<FlagDeclaringOp<Integer>> ops = new ArrayList<>();
- ops.add(new FlagDeclaringOp<>(clearAllFlags));
- for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
- if (f.canSet(StreamOpFlag.Type.OP)) {
- ops.add(new TestFlagExpectedOp<>(f.set(),
- known.clone(),
- EnumSet.noneOf(StreamOpFlag.class),
- notKnown.clone()));
- known.add(f);
- notKnown.remove(f);
- }
- }
- ops.add(new TestFlagExpectedOp<>(0,
- known.clone(),
- EnumSet.noneOf(StreamOpFlag.class),
- notKnown.clone()));
-
- TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
- @SuppressWarnings("rawtypes")
- FlagDeclaringOp[] opsArray = ops.toArray(new FlagDeclaringOp[ops.size()]);
-
- withData(data).ops(opsArray).
- without(StreamTestScenario.CLEAR_SIZED_SCENARIOS).
- exercise();
- }
-
- public void testFlagsSetAllClear() {
- EnumSet<StreamOpFlag> known = StreamOpFlagTestHelper.allStreamFlags();
- int setAllFlags = 0;
- for (StreamOpFlag f : EnumSet.allOf(StreamOpFlag.class)) {
- if (f.isStreamFlag()) {
- if (f.canSet(StreamOpFlag.Type.OP)) {
- setAllFlags |= f.set();
- } else {
- known.remove(f);
- }
- }
- }
-
- EnumSet<StreamOpFlag> notKnown = EnumSet.noneOf(StreamOpFlag.class);
-
- List<FlagDeclaringOp<Integer>> ops = new ArrayList<>();
- ops.add(new FlagDeclaringOp<>(setAllFlags));
- for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
- ops.add(new TestFlagExpectedOp<>(f.clear(),
- known.clone(),
- EnumSet.noneOf(StreamOpFlag.class),
- notKnown.clone()));
- known.remove(f);
- notKnown.add(f);
- }
- ops.add(new TestFlagExpectedOp<>(0,
- known.clone(),
- EnumSet.noneOf(StreamOpFlag.class),
- notKnown.clone()));
-
- TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
- @SuppressWarnings("rawtypes")
- FlagDeclaringOp[] opsArray = ops.toArray(new FlagDeclaringOp[ops.size()]);
-
-
- withData(data).ops(opsArray).
- without(StreamTestScenario.CLEAR_SIZED_SCENARIOS).
- exercise();
- }
-
- public void testFlagsParallelCollect() {
- testFlagsSetSequence(CollectorOps::collector);
- }
-
- private void testFlagsSetSequence(Supplier<StatefulTestOp<Integer>> cf) {
- EnumSet<StreamOpFlag> known = EnumSet.of(StreamOpFlag.ORDERED, StreamOpFlag.SIZED);
- EnumSet<StreamOpFlag> preserve = EnumSet.of(StreamOpFlag.DISTINCT, StreamOpFlag.SORTED);
-
- List<IntermediateTestOp<Integer, Integer>> ops = new ArrayList<>();
- for (StreamOpFlag f : EnumSet.of(StreamOpFlag.DISTINCT, StreamOpFlag.SORTED)) {
- ops.add(cf.get());
- ops.add(new TestFlagExpectedOp<>(f.set(),
- known.clone(),
- preserve.clone(),
- EnumSet.noneOf(StreamOpFlag.class)));
- known.add(f);
- preserve.remove(f);
- }
- ops.add(cf.get());
- ops.add(new TestFlagExpectedOp<>(0,
- known.clone(),
- preserve.clone(),
- EnumSet.noneOf(StreamOpFlag.class)));
-
- TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
- @SuppressWarnings("rawtypes")
- IntermediateTestOp[] opsArray = ops.toArray(new IntermediateTestOp[ops.size()]);
-
- withData(data).ops(opsArray).
- without(StreamTestScenario.CLEAR_SIZED_SCENARIOS).
- exercise();
- }
-
-
- public void testFlagsClearParallelCollect() {
- testFlagsClearSequence(CollectorOps::collector);
- }
-
- protected void testFlagsClearSequence(Supplier<StatefulTestOp<Integer>> cf) {
- EnumSet<StreamOpFlag> known = EnumSet.of(StreamOpFlag.ORDERED, StreamOpFlag.SIZED);
- EnumSet<StreamOpFlag> preserve = EnumSet.of(StreamOpFlag.DISTINCT, StreamOpFlag.SORTED);
- EnumSet<StreamOpFlag> notKnown = EnumSet.noneOf(StreamOpFlag.class);
-
- List<IntermediateTestOp<Integer, Integer>> ops = new ArrayList<>();
- for (StreamOpFlag f : EnumSet.of(StreamOpFlag.ORDERED, StreamOpFlag.DISTINCT, StreamOpFlag.SORTED)) {
- ops.add(cf.get());
- ops.add(new TestFlagExpectedOp<>(f.clear(),
- known.clone(),
- preserve.clone(),
- notKnown.clone()));
- known.remove(f);
- preserve.remove(f);
- notKnown.add(f);
- }
- ops.add(cf.get());
- ops.add(new TestFlagExpectedOp<>(0,
- known.clone(),
- preserve.clone(),
- notKnown.clone()));
-
- TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
- @SuppressWarnings("rawtypes")
- IntermediateTestOp[] opsArray = ops.toArray(new IntermediateTestOp[ops.size()]);
-
- withData(data).ops(opsArray).
- without(StreamTestScenario.CLEAR_SIZED_SCENARIOS).
- exercise();
- }
-
- public void testFlagsSizedOrderedParallelCollect() {
- EnumSet<StreamOpFlag> parKnown = EnumSet.of(StreamOpFlag.SIZED);
- EnumSet<StreamOpFlag> serKnown = parKnown.clone();
-
- List<IntermediateTestOp<Integer, Integer>> ops = new ArrayList<>();
- for (StreamOpFlag f : parKnown) {
- ops.add(CollectorOps.collector());
- ops.add(new ParSerTestFlagExpectedOp<>(f.clear(),
- parKnown,
- serKnown));
- serKnown.remove(f);
- }
- ops.add(CollectorOps.collector());
- ops.add(new ParSerTestFlagExpectedOp<>(0,
- parKnown,
- EnumSet.noneOf(StreamOpFlag.class)));
-
- TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
- @SuppressWarnings("rawtypes")
- IntermediateTestOp[] opsArray = ops.toArray(new IntermediateTestOp[ops.size()]);
-
- withData(data).ops(opsArray).exercise();
- }
-
- static class ParSerTestFlagExpectedOp<T> extends FlagDeclaringOp<T> {
- final EnumSet<StreamOpFlag> parKnown;
- final EnumSet<StreamOpFlag> serKnown;
-
- ParSerTestFlagExpectedOp(int flags, EnumSet<StreamOpFlag> known, EnumSet<StreamOpFlag> serKnown) {
- super(flags);
- this.parKnown = known;
- this.serKnown = serKnown;
- }
-
- @Override
- @SuppressWarnings({"unchecked", "rawtypes"})
- public Sink<T> opWrapSink(int flags, boolean parallel, Sink upstream) {
- assertFlags(flags, parallel);
- return upstream;
- }
-
- protected void assertFlags(int flags, boolean parallel) {
- if (parallel) {
- for (StreamOpFlag f : parKnown) {
- Assert.assertTrue(f.isKnown(flags), String.format("Flag %s is not known, but should be known.", f.toString()));
- }
-
- } else {
- for (StreamOpFlag f : serKnown) {
- Assert.assertTrue(f.isKnown(flags), String.format("Flag %s is not known, but should be known.", f.toString()));
- }
-
- }
- }
- }
-}
--- a/jdk/test/java/util/stream/boottest/java/util/stream/IntNodeTest.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,177 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.PrimitiveIterator;
-import java.util.Spliterators;
-import java.util.function.Function;
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-@Test
-public class IntNodeTest extends OpTestCase {
-
- @DataProvider(name = "nodes")
- public Object[][] createSizes() {
- List<Object[]> params = new ArrayList<>();
-
- for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
- int[] array = new int[size];
- for (int i = 0; i < array.length; i++) {
- array[i] = i;
- }
-
- List<Node<Integer>> nodes = new ArrayList<>();
-
- nodes.add(Nodes.node(array));
- nodes.add(degenerateTree(Spliterators.iterator(Arrays.spliterator(array))));
- nodes.add(tree(toList(array), l -> Nodes.node(toIntArray(l))));
- nodes.add(fill(array, Nodes.intBuilder(array.length)));
- nodes.add(fill(array, Nodes.intBuilder()));
-
- for (Node<Integer> node : nodes) {
- params.add(new Object[]{array, node});
- }
-
- }
-
- return params.toArray(new Object[0][]);
- }
-
- private static void assertEqualsListIntArray(List<Integer> list, int[] array) {
- assertEquals(list.size(), array.length);
- for (int i = 0; i < array.length; i++)
- assertEquals(array[i], (int) list.get(i));
- }
-
- private List<Integer> toList(int[] a) {
- List<Integer> l = new ArrayList<>();
- for (int i : a) {
- l.add(i);
- }
-
- return l;
- }
-
- private int[] toIntArray(List<Integer> l) {
- int[] a = new int[l.size()];
-
- int i = 0;
- for (Integer e : l) {
- a[i++] = e;
- }
- return a;
- }
-
- private Node.OfInt fill(int[] array, Node.Builder.OfInt nb) {
- nb.begin(array.length);
- for (int i : array)
- nb.accept(i);
- nb.end();
- return nb.build();
- }
-
- private Node.OfInt degenerateTree(PrimitiveIterator.OfInt it) {
- if (!it.hasNext()) {
- return Nodes.node(new int[0]);
- }
-
- int i = it.nextInt();
- if (it.hasNext()) {
- return new Nodes.ConcNode.OfInt(Nodes.node(new int[] {i}), degenerateTree(it));
- }
- else {
- return Nodes.node(new int[] {i});
- }
- }
-
- private Node.OfInt tree(List<Integer> l, Function<List<Integer>, Node.OfInt> m) {
- if (l.size() < 3) {
- return m.apply(l);
- }
- else {
- return new Nodes.ConcNode.OfInt(
- tree(l.subList(0, l.size() / 2), m),
- tree(l.subList(l.size() / 2, l.size()), m));
- }
- }
-
- @Test(dataProvider = "nodes")
- public void testAsArray(int[] array, Node.OfInt n) {
- assertEquals(n.asPrimitiveArray(), array);
- }
-
- @Test(dataProvider = "nodes")
- public void testFlattenAsArray(int[] array, Node.OfInt n) {
- assertEquals(Nodes.flattenInt(n).asPrimitiveArray(), array);
- }
-
- @Test(dataProvider = "nodes")
- public void testCopyTo(int[] array, Node.OfInt n) {
- int[] copy = new int[(int) n.count()];
- n.copyInto(copy, 0);
-
- assertEquals(copy, array);
- }
-
- @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
- public void testForEach(int[] array, Node.OfInt n) {
- List<Integer> l = new ArrayList<>((int) n.count());
- n.forEach((int e) -> {
- l.add(e);
- });
-
- assertEqualsListIntArray(l, array);
- }
-
- @Test(dataProvider = "nodes")
- public void testStreams(int[] array, Node.OfInt n) {
- TestData.OfInt data = TestData.Factory.ofNode("Node", n);
-
- exerciseOps(data, s -> s);
- exerciseTerminalOps(data, s -> s.toArray());
- }
-
- @Test(dataProvider = "nodes")
- public void testSpliterator(int[] array, Node.OfInt n) {
- SpliteratorTestHelper.testIntSpliterator(n::spliterator);
- }
-
- @Test(dataProvider = "nodes")
- public void testTruncate(int[] array, Node.OfInt n) {
- int[] nums = new int[] { 0, 1, array.length / 2, array.length - 1, array.length };
- for (int start : nums)
- for (int end : nums) {
- if (start < 0 || end < 0 || end < start || end > array.length)
- continue;
- Node.OfInt slice = n.truncate(start, end, Integer[]::new);
- int[] asArray = slice.asPrimitiveArray();
- for (int k = start; k < end; k++)
- assertEquals(array[k], asArray[k - start]);
- }
- }
-}
--- a/jdk/test/java/util/stream/boottest/java/util/stream/LongNodeTest.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,178 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.PrimitiveIterator;
-import java.util.Spliterators;
-import java.util.function.Function;
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-@Test
-public class LongNodeTest extends OpTestCase {
-
- @DataProvider(name = "nodes")
- public Object[][] createSizes() {
- List<Object[]> params = new ArrayList<>();
-
- for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
- long[] array = new long[size];
- for (int i = 0; i < array.length; i++) {
- array[i] = i;
- }
-
- List<Node<Long>> nodes = new ArrayList<>();
-
- nodes.add(Nodes.node(array));
- nodes.add(degenerateTree(Spliterators.iterator(Arrays.spliterator(array))));
- nodes.add(tree(toList(array), l -> Nodes.node(toLongArray(l))));
- nodes.add(fill(array, Nodes.longBuilder(array.length)));
- nodes.add(fill(array, Nodes.longBuilder()));
-
- for (Node<Long> node : nodes) {
- params.add(new Object[]{array, node});
- }
-
- }
-
- return params.toArray(new Object[0][]);
- }
-
- private static void assertEqualsListLongArray(List<Long> list, long[] array) {
- assertEquals(list.size(), array.length);
- for (int i = 0; i < array.length; i++)
- assertEquals(array[i], (long) list.get(i));
- }
-
- private List<Long> toList(long[] a) {
- List<Long> l = new ArrayList<>();
- for (long i : a) {
- l.add(i);
- }
-
- return l;
- }
-
- private long[] toLongArray(List<Long> l) {
- long[] a = new long[l.size()];
-
- int i = 0;
- for (Long e : l) {
- a[i++] = e;
- }
- return a;
- }
-
- private Node.OfLong fill(long[] array, Node.Builder.OfLong nb) {
- nb.begin(array.length);
- for (long i : array)
- nb.accept(i);
- nb.end();
- return nb.build();
- }
-
- private Node.OfLong degenerateTree(PrimitiveIterator.OfLong it) {
- if (!it.hasNext()) {
- return Nodes.node(new long[0]);
- }
-
- long i = it.nextLong();
- if (it.hasNext()) {
- return new Nodes.ConcNode.OfLong(Nodes.node(new long[] {i}), degenerateTree(it));
- }
- else {
- return Nodes.node(new long[] {i});
- }
- }
-
- private Node.OfLong tree(List<Long> l, Function<List<Long>, Node.OfLong> m) {
- if (l.size() < 3) {
- return m.apply(l);
- }
- else {
- return new Nodes.ConcNode.OfLong(
- tree(l.subList(0, l.size() / 2), m),
- tree(l.subList(l.size() / 2, l.size()), m));
- }
- }
-
- @Test(dataProvider = "nodes")
- public void testAsArray(long[] array, Node.OfLong n) {
- assertEquals(n.asPrimitiveArray(), array);
- }
-
- @Test(dataProvider = "nodes")
- public void testFlattenAsArray(long[] array, Node.OfLong n) {
- assertEquals(Nodes.flattenLong(n).asPrimitiveArray(), array);
- }
-
- @Test(dataProvider = "nodes")
- public void testCopyTo(long[] array, Node.OfLong n) {
- long[] copy = new long[(int) n.count()];
- n.copyInto(copy, 0);
-
- assertEquals(copy, array);
- }
-
- @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
- public void testForEach(long[] array, Node.OfLong n) {
- List<Long> l = new ArrayList<>((int) n.count());
- n.forEach((long e) -> {
- l.add(e);
- });
-
- assertEqualsListLongArray(l, array);
- }
-
- @Test(dataProvider = "nodes")
- public void testStreams(long[] array, Node.OfLong n) {
- TestData.OfLong data = TestData.Factory.ofNode("Node", n);
-
- exerciseOps(data, s -> s);
-
- exerciseTerminalOps(data, s -> s.toArray());
- }
-
- @Test(dataProvider = "nodes")
- public void testSpliterator(long[] array, Node.OfLong n) {
- SpliteratorTestHelper.testLongSpliterator(n::spliterator);
- }
-
- @Test(dataProvider = "nodes")
- public void testTruncate(long[] array, Node.OfLong n) {
- int[] nums = new int[] { 0, 1, array.length / 2, array.length - 1, array.length };
- for (int start : nums)
- for (int end : nums) {
- if (start < 0 || end < 0 || end < start || end > array.length)
- continue;
- Node.OfLong slice = n.truncate(start, end, Long[]::new);
- long[] asArray = slice.asPrimitiveArray();
- for (int k = start; k < end; k++)
- assertEquals(array[k], asArray[k - start]);
- }
- }
-}
--- a/jdk/test/java/util/stream/boottest/java/util/stream/NodeBuilderTest.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,236 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.function.DoubleConsumer;
-import java.util.function.Function;
-import java.util.function.IntConsumer;
-import java.util.function.LongConsumer;
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import static java.util.stream.LambdaTestHelpers.assertContents;
-import static java.util.stream.LambdaTestHelpers.countTo;
-import static org.testng.Assert.assertEquals;
-
-@Test
-public class NodeBuilderTest {
-
- List<Integer> sizes = Arrays.asList(0, 1, 4, 16, 256,
- 1023, 1024, 1025,
- 2047, 2048, 2049,
- 1024 * 32 - 1, 1024 * 32, 1024 * 32 + 1);
-
- @DataProvider(name = "Node.Builder")
- public Object[][] createNodeBuilders() {
- List<List<Integer>> ls = new ArrayList<>();
- for (int size : sizes) {
- ls.add(countTo(size));
- }
-
- List<Function<Integer, Node.Builder<Integer>>> ms = Arrays.asList(
- s -> Nodes.builder(),
- s -> Nodes.builder(s, LambdaTestHelpers.integerArrayGenerator)
- );
-
- Object[][] params = new Object[ls.size() * ms.size()][];
- int i = 0;
- for (List<Integer> l : ls) {
- for (Function<Integer, Node.Builder<Integer>> m : ms) {
- params[i++] = new Object[]{l, m};
- }
- }
-
- return params;
- }
-
- @Test(dataProvider = "Node.Builder", groups = { "serialization-hostile" })
- public void testIteration(List<Integer> l, Function<Integer, Node.Builder<Integer>> m) {
- Node.Builder<Integer> nb = m.apply(l.size());
- nb.begin(l.size());
- for (Integer i : l) {
- nb.accept(i);
- }
- nb.end();
-
- Node<Integer> n = nb.build();
- assertEquals(n.count(), l.size());
-
- {
- List<Integer> _l = new ArrayList<>();
- n.forEach(_l::add);
-
- assertContents(_l, l);
- }
- }
-
- // Node.Builder.OfInt
-
- @DataProvider(name = "Node.Builder<Integer>")
- public Object[][] createIntNodeBuilders() {
- List<List<Integer>> ls = new ArrayList<>();
- for (int size : sizes) {
- ls.add(countTo(size));
- }
-
- List<Function<Integer, Node.Builder<Integer>>> ms = Arrays.asList(
- s -> Nodes.intBuilder(),
- s -> Nodes.intBuilder(s)
- );
-
- Object[][] params = new Object[ls.size() * ms.size()][];
- int i = 0;
- for (List<Integer> l : ls) {
- for (Function<Integer, Node.Builder<Integer>> m : ms) {
- params[i++] = new Object[]{l, m};
- }
- }
-
- return params;
- }
-
- @Test(dataProvider = "Node.Builder<Integer>", groups = { "serialization-hostile" })
- public void testIntIteration(List<Integer> l, Function<Integer, Node.Builder.OfInt> m) {
- Node.Builder.OfInt nb = m.apply(l.size());
- nb.begin(l.size());
- for (Integer i : l) {
- nb.accept((int) i);
- }
- nb.end();
-
- Node.OfInt n = nb.build();
- assertEquals(n.count(), l.size());
-
- {
- List<Integer> _l = new ArrayList<>();
- n.forEach((IntConsumer) _l::add);
-
- assertContents(_l, l);
- }
-
- }
-
- // Node.Builder.OfLong
-
- @DataProvider(name = "Node.Builder<Long>")
- public Object[][] createLongNodeBuilders() {
- List<List<Long>> ls = new ArrayList<>();
- for (int size : sizes) {
- List<Long> l = new ArrayList<>();
- for (long i = 0; i < size; i++) {
- l.add(i);
- }
- ls.add(l);
- }
-
- List<Function<Integer, Node.Builder<Long>>> ms = Arrays.asList(
- s -> Nodes.longBuilder(),
- s -> Nodes.longBuilder(s)
- );
-
- Object[][] params = new Object[ls.size() * ms.size()][];
- int i = 0;
- for (List<Long> l : ls) {
- for (Function<Integer, Node.Builder<Long>> m : ms) {
- params[i++] = new Object[]{l, m};
- }
- }
-
- return params;
- }
-
- @Test(dataProvider = "Node.Builder<Long>")
- public void testLongIteration(List<Long> l, Function<Integer, Node.Builder.OfLong> m) {
- Node.Builder.OfLong nb = m.apply(l.size());
- nb.begin(l.size());
- for (Long i : l) {
- nb.accept((long) i);
- }
- nb.end();
-
- Node.OfLong n = nb.build();
- assertEquals(n.count(), l.size());
-
- {
- List<Long> _l = new ArrayList<>();
- n.forEach((LongConsumer) _l::add);
-
- assertContents(_l, l);
- }
-
- }
-
- // Node.Builder.OfDouble
-
- @DataProvider(name = "Node.Builder<Double>")
- public Object[][] createDoubleNodeBuilders() {
- List<List<Double>> ls = new ArrayList<>();
- for (int size : sizes) {
- List<Double> l = new ArrayList<>();
- for (long i = 0; i < size; i++) {
- l.add((double) i);
- }
- ls.add(l);
- }
-
- List<Function<Integer, Node.Builder<Double>>> ms = Arrays.asList(
- s -> Nodes.doubleBuilder(),
- s -> Nodes.doubleBuilder(s)
- );
-
- Object[][] params = new Object[ls.size() * ms.size()][];
- int i = 0;
- for (List<Double> l : ls) {
- for (Function<Integer, Node.Builder<Double>> m : ms) {
- params[i++] = new Object[]{l, m};
- }
- }
-
- return params;
- }
-
- @Test(dataProvider = "Node.Builder<Double>")
- public void testDoubleIteration(List<Double> l, Function<Integer, Node.Builder.OfDouble> m) {
- Node.Builder.OfDouble nb = m.apply(l.size());
- nb.begin(l.size());
- for (Double i : l) {
- nb.accept((double) i);
- }
- nb.end();
-
- Node.OfDouble n = nb.build();
- assertEquals(n.count(), l.size());
-
- {
- List<Double> _l = new ArrayList<>();
- n.forEach((DoubleConsumer) _l::add);
-
- assertContents(_l, l);
- }
-
- }
-}
--- a/jdk/test/java/util/stream/boottest/java/util/stream/NodeTest.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.function.Function;
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-@Test
-public class NodeTest extends OpTestCase {
-
- @DataProvider(name = "nodes")
- public Object[][] createSizes() {
- List<Object[]> params = new ArrayList<>();
-
- for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
- Integer[] array = new Integer[size];
- for (int i = 0; i < array.length; i++) {
- array[i] = i;
- }
-
- List<Node<Integer>> nodes = new ArrayList<>();
- nodes.add(Nodes.node(array));
- nodes.add(Nodes.node(Arrays.asList(array)));
- nodes.add(degenerateTree(Arrays.asList(array).iterator()));
- nodes.add(tree(Arrays.asList(array), l -> Nodes.node(l.toArray(new Integer[l.size()]))));
- nodes.add(tree(Arrays.asList(array), l -> Nodes.node(l)));
- nodes.add(fill(array, Nodes.builder(array.length, LambdaTestHelpers.integerArrayGenerator)));
- nodes.add(fill(array, Nodes.builder()));
-
- for (int i = 0; i < nodes.size(); i++) {
- params.add(new Object[]{array, nodes.get(i)});
- }
-
- }
-
- return params.toArray(new Object[0][]);
- }
-
- Node<Integer> fill(Integer[] array, Node.Builder<Integer> nb) {
- nb.begin(array.length);
- for (Integer i : array) {
- nb.accept(i);
- }
- nb.end();
- return nb.build();
- }
-
- Node<Integer> degenerateTree(Iterator<Integer> it) {
- if (!it.hasNext()) {
- return Nodes.node(Collections.emptyList());
- }
-
- Integer i = it.next();
- if (it.hasNext()) {
- return new Nodes.ConcNode<Integer>(Nodes.node(new Integer[] {i}), degenerateTree(it));
- }
- else {
- return Nodes.node(new Integer[]{i});
- }
- }
-
- Node<Integer> tree(List<Integer> l, Function<List<Integer>, Node<Integer>> m) {
- if (l.size() < 3) {
- return m.apply(l);
- }
- else {
- return new Nodes.ConcNode<>(
- tree(l.subList(0, l.size() / 2), m),
- tree(l.subList(l.size() / 2, l.size()), m ));
- }
- }
-
- @Test(dataProvider = "nodes")
- public void testAsArray(Integer[] array, Node<Integer> n) {
- assertEquals(n.asArray(LambdaTestHelpers.integerArrayGenerator), array);
- }
-
- @Test(dataProvider = "nodes")
- public void testFlattenAsArray(Integer[] array, Node<Integer> n) {
- assertEquals(Nodes.flatten(n, LambdaTestHelpers.integerArrayGenerator)
- .asArray(LambdaTestHelpers.integerArrayGenerator), array);
- }
-
- @Test(dataProvider = "nodes")
- public void testCopyTo(Integer[] array, Node<Integer> n) {
- Integer[] copy = new Integer[(int) n.count()];
- n.copyInto(copy, 0);
-
- assertEquals(copy, array);
- }
-
- @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
- public void testForEach(Integer[] array, Node<Integer> n) {
- List<Integer> l = new ArrayList<>((int) n.count());
- n.forEach(e -> l.add(e));
-
- assertEquals(l.toArray(), array);
- }
-
- @Test(dataProvider = "nodes")
- public void testStreams(Integer[] array, Node<Integer> n) {
- TestData<Integer, Stream<Integer>> data = TestData.Factory.ofRefNode("Node", n);
-
- exerciseOps(data, s -> s);
-
- exerciseTerminalOps(data, s -> s.toArray());
- }
-
- @Test(dataProvider = "nodes")
- public void testSpliterator(Integer[] array, Node<Integer> n) {
- SpliteratorTestHelper.testSpliterator(n::spliterator);
- }
-
- @Test(dataProvider = "nodes")
- public void testTruncate(Integer[] array, Node<Integer> n) {
- int[] nums = new int[] { 0, 1, array.length / 2, array.length - 1, array.length };
- for (int start : nums)
- for (int end : nums) {
- if (start < 0 || end < 0 || end < start || end > array.length)
- continue;
- Node<Integer> slice = n.truncate(start, end, Integer[]::new);
- Integer[] asArray = slice.asArray(Integer[]::new);
- for (int k = start; k < end; k++)
- assertEquals(array[k], asArray[k - start]);
- }
- }
-}
--- a/jdk/test/java/util/stream/boottest/java/util/stream/SliceSpliteratorTest.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,201 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Spliterator;
-
-import static java.util.stream.Collectors.toList;
-import static org.testng.Assert.assertEquals;
-
-/**
- * @bug 8012987
- */
-@Test
-public class SliceSpliteratorTest extends LoggingTestCase {
-
- static class UnorderedContentAsserter<T> implements SpliteratorTestHelper.ContentAsserter<T> {
- Collection<T> source;
-
- UnorderedContentAsserter(Collection<T> source) {
- this.source = source;
- }
-
- @Override
- public void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered) {
- if (isOrdered) {
- assertEquals(actual, expected);
- }
- else {
- assertEquals(actual.size(), expected.size());
- assertTrue(source.containsAll(actual));
- }
- }
- }
-
- interface SliceTester {
- void test(int size, int skip, int limit);
- }
-
- @DataProvider(name = "sliceSpliteratorDataProvider")
- public static Object[][] sliceSpliteratorDataProvider() {
- List<Object[]> data = new ArrayList<>();
-
- // SIZED/SUBSIZED slice spliterator
-
- {
- SliceTester r = (size, skip, limit) -> {
- final Collection<Integer> source = IntStream.range(0, size).boxed().collect(toList());
-
- SpliteratorTestHelper.testSpliterator(() -> {
- Spliterator<Integer> s = Arrays.spliterator(source.stream().toArray(Integer[]::new));
-
- return new StreamSpliterators.SliceSpliterator.OfRef<>(s, skip, limit);
- });
- };
- data.add(new Object[]{"StreamSpliterators.SliceSpliterator.OfRef", r});
- }
-
- {
- SliceTester r = (size, skip, limit) -> {
- final Collection<Integer> source = IntStream.range(0, size).boxed().collect(toList());
-
- SpliteratorTestHelper.testIntSpliterator(() -> {
- Spliterator.OfInt s = Arrays.spliterator(source.stream().mapToInt(i->i).toArray());
-
- return new StreamSpliterators.SliceSpliterator.OfInt(s, skip, limit);
- });
- };
- data.add(new Object[]{"StreamSpliterators.SliceSpliterator.OfInt", r});
- }
-
- {
- SliceTester r = (size, skip, limit) -> {
- final Collection<Long> source = LongStream.range(0, size).boxed().collect(toList());
-
- SpliteratorTestHelper.testLongSpliterator(() -> {
- Spliterator.OfLong s = Arrays.spliterator(source.stream().mapToLong(i->i).toArray());
-
- return new StreamSpliterators.SliceSpliterator.OfLong(s, skip, limit);
- });
- };
- data.add(new Object[]{"StreamSpliterators.SliceSpliterator.OfLong", r});
- }
-
- {
- SliceTester r = (size, skip, limit) -> {
- final Collection<Double> source = LongStream.range(0, size).asDoubleStream().boxed().collect(toList());
-
- SpliteratorTestHelper.testDoubleSpliterator(() -> {
- Spliterator.OfDouble s = Arrays.spliterator(source.stream().mapToDouble(i->i).toArray());
-
- return new StreamSpliterators.SliceSpliterator.OfDouble(s, skip, limit);
- });
- };
- data.add(new Object[]{"StreamSpliterators.SliceSpliterator.OfLong", r});
- }
-
-
- // Unordered slice spliterator
-
- {
- SliceTester r = (size, skip, limit) -> {
- final Collection<Integer> source = IntStream.range(0, size).boxed().collect(toList());
- final UnorderedContentAsserter<Integer> uca = new UnorderedContentAsserter<>(source);
-
- SpliteratorTestHelper.testSpliterator(() -> {
- Spliterator<Integer> s = Arrays.spliterator(source.stream().toArray(Integer[]::new));
-
- return new StreamSpliterators.UnorderedSliceSpliterator.OfRef<>(s, skip, limit);
- }, uca);
- };
- data.add(new Object[]{"StreamSpliterators.UnorderedSliceSpliterator.OfRef", r});
- }
-
- {
- SliceTester r = (size, skip, limit) -> {
- final Collection<Integer> source = IntStream.range(0, size).boxed().collect(toList());
- final UnorderedContentAsserter<Integer> uca = new UnorderedContentAsserter<>(source);
-
- SpliteratorTestHelper.testIntSpliterator(() -> {
- Spliterator.OfInt s = Arrays.spliterator(source.stream().mapToInt(i->i).toArray());
-
- return new StreamSpliterators.UnorderedSliceSpliterator.OfInt(s, skip, limit);
- }, uca);
- };
- data.add(new Object[]{"StreamSpliterators.UnorderedSliceSpliterator.OfInt", r});
- }
-
- {
- SliceTester r = (size, skip, limit) -> {
- final Collection<Long> source = LongStream.range(0, size).boxed().collect(toList());
- final UnorderedContentAsserter<Long> uca = new UnorderedContentAsserter<>(source);
-
- SpliteratorTestHelper.testLongSpliterator(() -> {
- Spliterator.OfLong s = Arrays.spliterator(source.stream().mapToLong(i->i).toArray());
-
- return new StreamSpliterators.UnorderedSliceSpliterator.OfLong(s, skip, limit);
- }, uca);
- };
- data.add(new Object[]{"StreamSpliterators.UnorderedSliceSpliterator.OfLong", r});
- }
-
- {
- SliceTester r = (size, skip, limit) -> {
- final Collection<Double> source = LongStream.range(0, size).asDoubleStream().boxed().collect(toList());
- final UnorderedContentAsserter<Double> uca = new UnorderedContentAsserter<>(source);
-
- SpliteratorTestHelper.testDoubleSpliterator(() -> {
- Spliterator.OfDouble s = Arrays.spliterator(LongStream.range(0, SIZE).asDoubleStream().toArray());
-
- return new StreamSpliterators.UnorderedSliceSpliterator.OfDouble(s, skip, limit);
- }, uca);
- };
- data.add(new Object[]{"StreamSpliterators.UnorderedSliceSpliterator.OfLong", r});
- }
-
- return data.toArray(new Object[0][]);
- }
-
- static final int SIZE = 256;
-
- static final int STEP = 32;
-
- @Test(dataProvider = "sliceSpliteratorDataProvider")
- public void testSliceSpliterator(String description, SliceTester r) {
- setContext("size", SIZE);
- for (int skip = 0; skip < SIZE; skip += STEP) {
- setContext("skip", skip);
- for (int limit = 0; limit < SIZE; limit += STEP) {
- setContext("limit", skip);
- r.test(SIZE, skip, limit);
- }
- }
- }
-}
--- a/jdk/test/java/util/stream/boottest/java/util/stream/SpinedBufferTest.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,370 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import java.util.*;
-import java.util.function.DoubleConsumer;
-import java.util.function.IntConsumer;
-import java.util.function.LongConsumer;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-
-@Test
-public class SpinedBufferTest {
-
- // Create sizes around the boundary of spines
- static List<Integer> sizes;
- static {
- try {
- sizes = IntStream.range(0, 15)
- .map(i -> 1 << i)
- .flatMap(i -> Arrays.stream(new int[] { i-2, i-1, i, i+1, i+2 }))
- .filter(i -> i >= 0)
- .boxed()
- .distinct()
- .collect(Collectors.toList());
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- private static final int TEST_SIZE = 5000;
-
- // SpinedBuffer
-
- @DataProvider(name = "SpinedBuffer")
- public Object[][] createSpinedBuffer() {
- List<Object[]> params = new ArrayList<>();
-
- for (int size : sizes) {
- int[] array = IntStream.range(0, size).toArray();
-
- SpinedBuffer<Integer> sb = new SpinedBuffer<>();
- Arrays.stream(array).boxed().forEach(sb);
- params.add(new Object[]{array, sb});
-
- sb = new SpinedBuffer<>(size / 2);
- Arrays.stream(array).boxed().forEach(sb);
- params.add(new Object[]{array, sb});
-
- sb = new SpinedBuffer<>(size);
- Arrays.stream(array).boxed().forEach(sb);
- params.add(new Object[]{array, sb});
-
- sb = new SpinedBuffer<>(size * 2);
- Arrays.stream(array).boxed().forEach(sb);
- params.add(new Object[]{array, sb});
- }
-
- return params.toArray(new Object[0][]);
- }
-
- @Test(dataProvider = "SpinedBuffer")
- public void testSpliterator(int[] array, SpinedBuffer<Integer> sb) {
- assertEquals(sb.count(), array.length);
- assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
-
- SpliteratorTestHelper.testSpliterator(sb::spliterator);
- }
-
- @Test(dataProvider = "SpinedBuffer", groups = { "serialization-hostile" })
- public void testLastSplit(int[] array, SpinedBuffer<Integer> sb) {
- Spliterator<Integer> spliterator = sb.spliterator();
- Spliterator<Integer> split = spliterator.trySplit();
- long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
- long lastSplitSize = spliterator.getExactSizeIfKnown();
- splitSizes += lastSplitSize;
-
- assertEquals(splitSizes, array.length);
-
- List<Integer> contentOfLastSplit = new ArrayList<>();
- spliterator.forEachRemaining(contentOfLastSplit::add);
-
- assertEquals(contentOfLastSplit.size(), lastSplitSize);
-
- List<Integer> end = Arrays.stream(array)
- .boxed()
- .skip(array.length - lastSplitSize)
- .collect(Collectors.toList());
- assertEquals(contentOfLastSplit, end);
- }
-
- @Test(groups = { "serialization-hostile" })
- public void testSpinedBuffer() {
- List<Integer> list1 = new ArrayList<>();
- List<Integer> list2 = new ArrayList<>();
- SpinedBuffer<Integer> sb = new SpinedBuffer<>();
- for (int i = 0; i < TEST_SIZE; i++) {
- list1.add(i);
- sb.accept(i);
- }
- Iterator<Integer> it = sb.iterator();
- for (int i = 0; i < TEST_SIZE; i++)
- list2.add(it.next());
- assertFalse(it.hasNext());
- assertEquals(list1, list2);
-
- for (int i = 0; i < TEST_SIZE; i++)
- assertEquals(sb.get(i), (Integer) i, Integer.toString(i));
-
- list2.clear();
- sb.forEach(list2::add);
- assertEquals(list1, list2);
- Integer[] array = sb.asArray(LambdaTestHelpers.integerArrayGenerator);
- list2.clear();
- for (Integer i : array)
- list2.add(i);
- assertEquals(list1, list2);
- }
-
- // IntSpinedBuffer
-
- @DataProvider(name = "IntSpinedBuffer")
- public Object[][] createIntSpinedBuffer() {
- List<Object[]> params = new ArrayList<>();
-
- for (int size : sizes) {
- int[] array = IntStream.range(0, size).toArray();
- SpinedBuffer.OfInt sb = new SpinedBuffer.OfInt();
- Arrays.stream(array).forEach(sb);
-
- params.add(new Object[]{array, sb});
- }
-
- return params.toArray(new Object[0][]);
- }
-
- @Test(dataProvider = "IntSpinedBuffer")
- public void testIntSpliterator(int[] array, SpinedBuffer.OfInt sb) {
- assertEquals(sb.count(), array.length);
- assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
-
- SpliteratorTestHelper.testIntSpliterator(sb::spliterator);
- }
-
- @Test(dataProvider = "IntSpinedBuffer", groups = { "serialization-hostile" })
- public void testIntLastSplit(int[] array, SpinedBuffer.OfInt sb) {
- Spliterator.OfInt spliterator = sb.spliterator();
- Spliterator.OfInt split = spliterator.trySplit();
- long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
- long lastSplitSize = spliterator.getExactSizeIfKnown();
- splitSizes += lastSplitSize;
-
- assertEquals(splitSizes, array.length);
-
- List<Integer> contentOfLastSplit = new ArrayList<>();
- spliterator.forEachRemaining((IntConsumer) contentOfLastSplit::add);
-
- assertEquals(contentOfLastSplit.size(), lastSplitSize);
-
- List<Integer> end = Arrays.stream(array)
- .boxed()
- .skip(array.length - lastSplitSize)
- .collect(Collectors.toList());
- assertEquals(contentOfLastSplit, end);
- }
-
- @Test(groups = { "serialization-hostile" })
- public void testIntSpinedBuffer() {
- List<Integer> list1 = new ArrayList<>();
- List<Integer> list2 = new ArrayList<>();
- SpinedBuffer.OfInt sb = new SpinedBuffer.OfInt();
- for (int i = 0; i < TEST_SIZE; i++) {
- list1.add(i);
- sb.accept(i);
- }
- PrimitiveIterator.OfInt it = sb.iterator();
- for (int i = 0; i < TEST_SIZE; i++)
- list2.add(it.nextInt());
- assertFalse(it.hasNext());
- assertEquals(list1, list2);
-
- for (int i = 0; i < TEST_SIZE; i++)
- assertEquals(sb.get(i), i, Integer.toString(i));
-
- list2.clear();
- sb.forEach((int i) -> list2.add(i));
- assertEquals(list1, list2);
- int[] array = sb.asPrimitiveArray();
- list2.clear();
- for (int i : array)
- list2.add(i);
- assertEquals(list1, list2);
- }
-
- // LongSpinedBuffer
-
- @DataProvider(name = "LongSpinedBuffer")
- public Object[][] createLongSpinedBuffer() {
- List<Object[]> params = new ArrayList<>();
-
- for (int size : sizes) {
- long[] array = LongStream.range(0, size).toArray();
- SpinedBuffer.OfLong sb = new SpinedBuffer.OfLong();
- Arrays.stream(array).forEach(sb);
-
- params.add(new Object[]{array, sb});
- }
-
- return params.toArray(new Object[0][]);
- }
-
- @Test(dataProvider = "LongSpinedBuffer")
- public void testLongSpliterator(long[] array, SpinedBuffer.OfLong sb) {
- assertEquals(sb.count(), array.length);
- assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
-
- SpliteratorTestHelper.testLongSpliterator(sb::spliterator);
- }
-
- @Test(dataProvider = "LongSpinedBuffer", groups = { "serialization-hostile" })
- public void testLongLastSplit(long[] array, SpinedBuffer.OfLong sb) {
- Spliterator.OfLong spliterator = sb.spliterator();
- Spliterator.OfLong split = spliterator.trySplit();
- long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
- long lastSplitSize = spliterator.getExactSizeIfKnown();
- splitSizes += lastSplitSize;
-
- assertEquals(splitSizes, array.length);
-
- List<Long> contentOfLastSplit = new ArrayList<>();
- spliterator.forEachRemaining((LongConsumer) contentOfLastSplit::add);
-
- assertEquals(contentOfLastSplit.size(), lastSplitSize);
-
- List<Long> end = Arrays.stream(array)
- .boxed()
- .skip(array.length - lastSplitSize)
- .collect(Collectors.toList());
- assertEquals(contentOfLastSplit, end);
- }
-
- @Test(groups = { "serialization-hostile" })
- public void testLongSpinedBuffer() {
- List<Long> list1 = new ArrayList<>();
- List<Long> list2 = new ArrayList<>();
- SpinedBuffer.OfLong sb = new SpinedBuffer.OfLong();
- for (long i = 0; i < TEST_SIZE; i++) {
- list1.add(i);
- sb.accept(i);
- }
- PrimitiveIterator.OfLong it = sb.iterator();
- for (int i = 0; i < TEST_SIZE; i++)
- list2.add(it.nextLong());
- assertFalse(it.hasNext());
- assertEquals(list1, list2);
-
- for (int i = 0; i < TEST_SIZE; i++)
- assertEquals(sb.get(i), i, Long.toString(i));
-
- list2.clear();
- sb.forEach((long i) -> list2.add(i));
- assertEquals(list1, list2);
- long[] array = sb.asPrimitiveArray();
- list2.clear();
- for (long i : array)
- list2.add(i);
- assertEquals(list1, list2);
- }
-
- // DoubleSpinedBuffer
-
- @DataProvider(name = "DoubleSpinedBuffer")
- public Object[][] createDoubleSpinedBuffer() {
- List<Object[]> params = new ArrayList<>();
-
- for (int size : sizes) {
- // @@@ replace with double range when implemented
- double[] array = LongStream.range(0, size).asDoubleStream().toArray();
- SpinedBuffer.OfDouble sb = new SpinedBuffer.OfDouble();
- Arrays.stream(array).forEach(sb);
-
- params.add(new Object[]{array, sb});
- }
-
- return params.toArray(new Object[0][]);
- }
-
- @Test(dataProvider = "DoubleSpinedBuffer")
- public void testDoubleSpliterator(double[] array, SpinedBuffer.OfDouble sb) {
- assertEquals(sb.count(), array.length);
- assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
-
- SpliteratorTestHelper.testDoubleSpliterator(sb::spliterator);
- }
-
- @Test(dataProvider = "DoubleSpinedBuffer", groups = { "serialization-hostile" })
- public void testLongLastSplit(double[] array, SpinedBuffer.OfDouble sb) {
- Spliterator.OfDouble spliterator = sb.spliterator();
- Spliterator.OfDouble split = spliterator.trySplit();
- long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
- long lastSplitSize = spliterator.getExactSizeIfKnown();
- splitSizes += lastSplitSize;
-
- assertEquals(splitSizes, array.length);
-
- List<Double> contentOfLastSplit = new ArrayList<>();
- spliterator.forEachRemaining((DoubleConsumer) contentOfLastSplit::add);
-
- assertEquals(contentOfLastSplit.size(), lastSplitSize);
-
- List<Double> end = Arrays.stream(array)
- .boxed()
- .skip(array.length - lastSplitSize)
- .collect(Collectors.toList());
- assertEquals(contentOfLastSplit, end);
- }
-
- @Test(groups = { "serialization-hostile" })
- public void testDoubleSpinedBuffer() {
- List<Double> list1 = new ArrayList<>();
- List<Double> list2 = new ArrayList<>();
- SpinedBuffer.OfDouble sb = new SpinedBuffer.OfDouble();
- for (long i = 0; i < TEST_SIZE; i++) {
- list1.add((double) i);
- sb.accept((double) i);
- }
- PrimitiveIterator.OfDouble it = sb.iterator();
- for (int i = 0; i < TEST_SIZE; i++)
- list2.add(it.nextDouble());
- assertFalse(it.hasNext());
- assertEquals(list1, list2);
-
- for (int i = 0; i < TEST_SIZE; i++)
- assertEquals(sb.get(i), (double) i, Double.toString(i));
-
- list2.clear();
- sb.forEach((double i) -> list2.add(i));
- assertEquals(list1, list2);
- double[] array = sb.asPrimitiveArray();
- list2.clear();
- for (double i : array)
- list2.add(i);
- assertEquals(list1, list2);
- }
-}
--- a/jdk/test/java/util/stream/boottest/java/util/stream/StreamFlagsTest.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import org.testng.annotations.Test;
-
-import java.util.*;
-import java.util.stream.Stream;
-import java.util.stream.StreamOpFlag;
-import java.util.stream.Streams;
-
-import static java.util.stream.StreamOpFlag.*;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-
-/**
- * StreamFlagsTest
- *
- * @author Brian Goetz
- */
-@Test
-public class StreamFlagsTest {
- Stream<String> arrayList = new ArrayList<String>().stream();
- Stream<String> linkedList = new LinkedList<String>().stream();
- Stream<String> hashSet = new HashSet<String>().stream();
- Stream<String> treeSet = new TreeSet<String>().stream();
- Stream<String> linkedHashSet = new LinkedHashSet<String>().stream();
- Stream<String> repeat = Stream.generate(() -> "");
-
- Stream<?>[] streams = { arrayList, linkedList, hashSet, treeSet, linkedHashSet, repeat };
-
- private void assertFlags(int value, EnumSet<StreamOpFlag> setFlags, EnumSet<StreamOpFlag> clearFlags) {
- for (StreamOpFlag flag : setFlags)
- assertTrue(flag.isKnown(value));
- for (StreamOpFlag flag : clearFlags)
- assertTrue(!flag.isKnown(value));
- }
-
- public void testBaseStreams() {
- Stream<String> arrayList = new ArrayList<String>().stream();
- Stream<String> linkedList = new LinkedList<String>().stream();
- Stream<String> hashSet = new HashSet<String>().stream();
- Stream<String> treeSet = new TreeSet<String>().stream();
- Stream<String> linkedHashSet = new LinkedHashSet<String>().stream();
- Stream<String> repeat = Stream.generate(() -> "");
-
- assertFlags(OpTestCase.getStreamFlags(arrayList),
- EnumSet.of(ORDERED, SIZED),
- EnumSet.of(DISTINCT, SORTED, SHORT_CIRCUIT));
- assertFlags(OpTestCase.getStreamFlags(linkedList),
- EnumSet.of(ORDERED, SIZED),
- EnumSet.of(DISTINCT, SORTED, SHORT_CIRCUIT));
- assertFlags(OpTestCase.getStreamFlags(hashSet),
- EnumSet.of(SIZED, DISTINCT),
- EnumSet.of(ORDERED, SORTED, SHORT_CIRCUIT));
- assertFlags(OpTestCase.getStreamFlags(treeSet),
- EnumSet.of(ORDERED, SIZED, DISTINCT, SORTED),
- EnumSet.of(SHORT_CIRCUIT));
- assertFlags(OpTestCase.getStreamFlags(linkedHashSet),
- EnumSet.of(ORDERED, DISTINCT, SIZED),
- EnumSet.of(SORTED, SHORT_CIRCUIT));
- assertFlags(OpTestCase.getStreamFlags(repeat),
- EnumSet.noneOf(StreamOpFlag.class),
- EnumSet.of(DISTINCT, SORTED, SHORT_CIRCUIT));
- }
-
- public void testFilter() {
- for (Stream<?> s : streams) {
- int baseFlags = OpTestCase.getStreamFlags(s);
- int filteredFlags = OpTestCase.getStreamFlags(s.filter((Object e) -> true));
- int expectedFlags = baseFlags & ~SIZED.set();
-
- assertEquals(filteredFlags, expectedFlags);
- }
- }
-}
--- a/jdk/test/java/util/stream/boottest/java/util/stream/StreamOpFlagsTest.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,381 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import org.testng.annotations.Test;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Spliterator;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.ToDoubleFunction;
-import java.util.function.ToIntFunction;
-import java.util.function.ToLongFunction;
-
-import static java.util.stream.Collectors.toList;
-import static java.util.stream.StreamOpFlag.*;
-import static org.testng.Assert.*;
-import static org.testng.Assert.assertEquals;
-
-@Test
-public class StreamOpFlagsTest {
-
- public void testNullCombine() {
- int sourceFlags = StreamOpFlag.IS_SIZED;
-
- assertEquals(sourceFlags, toStreamFlags(combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE)));
- }
-
- public void testInitialOpFlagsFromSourceFlags() {
- List<StreamOpFlag> flags = new ArrayList<>(StreamOpFlagTestHelper.allStreamFlags());
- for (int i = 0; i < (1 << flags.size()); i++) {
- int sourceFlags = 0;
- for (int f = 0; f < flags.size(); f++) {
- if ((i & (1 << f)) != 0) {
- sourceFlags |= flags.get(f).set();
- }
- }
-
- int opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
- assertEquals(opsFlags, (~(sourceFlags << 1)) & StreamOpFlag.INITIAL_OPS_VALUE);
- }
- }
-
- public void testSameCombine() {
- for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
- int sourceFlags = f.set();
- int opsFlags;
-
- opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
- opsFlags = combineOpFlags(f.set(), opsFlags);
- assertEquals(sourceFlags, toStreamFlags(opsFlags));
- }
- }
-
- public void testOpClear() {
- for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
- // Clear when source not set
- int sourceFlags = 0;
- int opsFlags;
-
- opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
- opsFlags = combineOpFlags(f.clear(), opsFlags);
- assertEquals(sourceFlags, toStreamFlags(opsFlags));
-
- // Clear when source set
- sourceFlags = f.set();
-
- opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
- opsFlags = combineOpFlags(f.clear(), opsFlags);
- assertEquals(0, toStreamFlags(opsFlags));
- }
- }
-
- public void testOpInject() {
- for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
- // Set when source not set
- int sourceFlags = 0;
- int opsFlags;
-
- opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
- opsFlags = combineOpFlags(f.set(), opsFlags);
- assertEquals(f.set(), toStreamFlags(opsFlags));
-
- // Set when source set
- sourceFlags = f.set();
-
- opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
- opsFlags = combineOpFlags(f.set(), opsFlags);
- assertEquals(sourceFlags, toStreamFlags(opsFlags));
- }
- }
-
- public void testPairSet() {
- List<Integer> sourceFlagsList
- = StreamOpFlagTestHelper.allStreamFlags().stream().map(StreamOpFlag::set).collect(toList());
- sourceFlagsList.add(0, 0);
-
- for (int sourceFlags : sourceFlagsList) {
- for (StreamOpFlag f1 : StreamOpFlagTestHelper.allStreamFlags()) {
- for (StreamOpFlag f2 : StreamOpFlagTestHelper.allStreamFlags()) {
- int opsFlags;
-
- opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
- opsFlags = combineOpFlags(f1.set(), opsFlags);
- opsFlags = combineOpFlags(f2.set(), opsFlags);
- assertEquals(sourceFlags | f1.set() | f2.set(), toStreamFlags(opsFlags));
- }
- }
- }
- }
-
- public void testPairSetAndClear() {
- List<Integer> sourceFlagsList
- = StreamOpFlagTestHelper.allStreamFlags().stream().map(StreamOpFlag::set).collect(toList());
- sourceFlagsList.add(0, 0);
-
- for (int sourceFlags : sourceFlagsList) {
- for (StreamOpFlag f1 : StreamOpFlagTestHelper.allStreamFlags()) {
- for (StreamOpFlag f2 : StreamOpFlagTestHelper.allStreamFlags()) {
- int opsFlags;
-
- opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
- opsFlags = combineOpFlags(f1.set(), opsFlags);
- opsFlags = combineOpFlags(f2.clear(), opsFlags);
- if (f1 == f2)
- assertEquals((f2.set() == sourceFlags) ? 0 : sourceFlags, toStreamFlags(opsFlags));
- else
- assertEquals((f2.set() == sourceFlags) ? f1.set() : sourceFlags | f1.set(), toStreamFlags(opsFlags));
- }
- }
- }
- }
-
- public void testShortCircuit() {
- int opsFlags = combineOpFlags(0, StreamOpFlag.INITIAL_OPS_VALUE);
- assertFalse(StreamOpFlag.SHORT_CIRCUIT.isKnown(opsFlags));
-
- opsFlags = combineOpFlags(StreamOpFlag.IS_SHORT_CIRCUIT, opsFlags);
- assertTrue(StreamOpFlag.SHORT_CIRCUIT.isKnown(opsFlags));
-
- opsFlags = combineOpFlags(0, opsFlags);
- assertTrue(StreamOpFlag.SHORT_CIRCUIT.isKnown(opsFlags));
- }
-
- public void testApplySourceFlags() {
- int sourceFlags = StreamOpFlag.IS_SIZED | StreamOpFlag.IS_DISTINCT;
-
- List<Integer> ops = Arrays.asList(StreamOpFlag.NOT_SIZED, StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
-
- int opsFlags = StreamOpFlag.combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
- for (int opFlags : ops) {
- opsFlags = combineOpFlags(opFlags, opsFlags);
- }
- assertFalse(StreamOpFlag.SIZED.isKnown(opsFlags));
- assertTrue(StreamOpFlag.SIZED.isCleared(opsFlags));
- assertFalse(StreamOpFlag.SIZED.isPreserved(opsFlags));
- assertTrue(StreamOpFlag.DISTINCT.isKnown(opsFlags));
- assertFalse(StreamOpFlag.DISTINCT.isCleared(opsFlags));
- assertFalse(StreamOpFlag.DISTINCT.isPreserved(opsFlags));
- assertTrue(StreamOpFlag.SORTED.isKnown(opsFlags));
- assertFalse(StreamOpFlag.SORTED.isCleared(opsFlags));
- assertFalse(StreamOpFlag.SORTED.isPreserved(opsFlags));
- assertTrue(StreamOpFlag.ORDERED.isKnown(opsFlags));
- assertFalse(StreamOpFlag.ORDERED.isCleared(opsFlags));
- assertFalse(StreamOpFlag.ORDERED.isPreserved(opsFlags));
-
- int streamFlags = toStreamFlags(opsFlags);
- assertFalse(StreamOpFlag.SIZED.isKnown(streamFlags));
- assertTrue(StreamOpFlag.DISTINCT.isKnown(streamFlags));
- assertTrue(StreamOpFlag.SORTED.isKnown(streamFlags));
- assertTrue(StreamOpFlag.ORDERED.isKnown(streamFlags));
- }
-
- public void testSpliteratorMask() {
- assertSpliteratorMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
- assertSpliteratorMask(StreamOpFlag.DISTINCT.clear(), 0);
-
- assertSpliteratorMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
- assertSpliteratorMask(StreamOpFlag.SORTED.clear(), 0);
-
- assertSpliteratorMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
- assertSpliteratorMask(StreamOpFlag.ORDERED.clear(), 0);
-
- assertSpliteratorMask(StreamOpFlag.SIZED.set(), StreamOpFlag.IS_SIZED);
- assertSpliteratorMask(StreamOpFlag.SIZED.clear(), 0);
-
- assertSpliteratorMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
- assertSpliteratorMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
- }
-
- private void assertSpliteratorMask(int actual, int expected) {
- assertEquals(actual & StreamOpFlag.SPLITERATOR_CHARACTERISTICS_MASK, expected);
- }
-
- public void testStreamMask() {
- assertStreamMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
- assertStreamMask(StreamOpFlag.DISTINCT.clear(), 0);
-
- assertStreamMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
- assertStreamMask(StreamOpFlag.SORTED.clear(), 0);
-
- assertStreamMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
- assertStreamMask(StreamOpFlag.ORDERED.clear(), 0);
-
- assertStreamMask(StreamOpFlag.SIZED.set(), StreamOpFlag.IS_SIZED);
- assertStreamMask(StreamOpFlag.SIZED.clear(), 0);
-
- assertStreamMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
- assertStreamMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
- }
-
- private void assertStreamMask(int actual, int expected) {
- assertEquals(actual & StreamOpFlag.STREAM_MASK, expected);
- }
-
- public void testOpMask() {
- assertOpMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
- assertOpMask(StreamOpFlag.DISTINCT.clear(), StreamOpFlag.NOT_DISTINCT);
-
- assertOpMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
- assertOpMask(StreamOpFlag.SORTED.clear(), StreamOpFlag.NOT_SORTED);
-
- assertOpMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
- assertOpMask(StreamOpFlag.ORDERED.clear(), StreamOpFlag.NOT_ORDERED);
-
- assertOpMask(StreamOpFlag.SIZED.set(), 0);
- assertOpMask(StreamOpFlag.SIZED.clear(), StreamOpFlag.NOT_SIZED);
-
- assertOpMask(StreamOpFlag.SHORT_CIRCUIT.set(), StreamOpFlag.IS_SHORT_CIRCUIT);
- assertOpMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
- }
-
- private void assertOpMask(int actual, int expected) {
- assertEquals(actual & StreamOpFlag.OP_MASK, expected);
- }
-
- public void testTerminalOpMask() {
- assertTerminalOpMask(StreamOpFlag.DISTINCT.set(), 0);
- assertTerminalOpMask(StreamOpFlag.DISTINCT.clear(), 0);
-
- assertTerminalOpMask(StreamOpFlag.SORTED.set(), 0);
- assertTerminalOpMask(StreamOpFlag.SORTED.clear(), 0);
-
- assertTerminalOpMask(StreamOpFlag.ORDERED.set(), 0);
- assertTerminalOpMask(StreamOpFlag.ORDERED.clear(), StreamOpFlag.NOT_ORDERED);
-
- assertTerminalOpMask(StreamOpFlag.SIZED.set(), 0);
- assertTerminalOpMask(StreamOpFlag.SIZED.clear(), 0);
-
- assertTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.set(), StreamOpFlag.IS_SHORT_CIRCUIT);
- assertTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
- }
-
- private void assertTerminalOpMask(int actual, int expected) {
- assertEquals(actual & StreamOpFlag.TERMINAL_OP_MASK, expected);
- }
-
- public void testUpstreamTerminalOpMask() {
- assertUpstreamTerminalOpMask(StreamOpFlag.DISTINCT.set(), 0);
- assertUpstreamTerminalOpMask(StreamOpFlag.DISTINCT.clear(), 0);
-
- assertUpstreamTerminalOpMask(StreamOpFlag.SORTED.set(), 0);
- assertUpstreamTerminalOpMask(StreamOpFlag.SORTED.clear(), 0);
-
- assertUpstreamTerminalOpMask(StreamOpFlag.ORDERED.set(), 0);
- assertUpstreamTerminalOpMask(StreamOpFlag.ORDERED.clear(), StreamOpFlag.NOT_ORDERED);
-
- assertUpstreamTerminalOpMask(StreamOpFlag.SIZED.set(), 0);
- assertUpstreamTerminalOpMask(StreamOpFlag.SIZED.clear(), 0);
-
- assertUpstreamTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
- assertUpstreamTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
- }
-
- private void assertUpstreamTerminalOpMask(int actual, int expected) {
- assertEquals(actual & StreamOpFlag.UPSTREAM_TERMINAL_OP_MASK, expected);
- }
-
- public void testSpliteratorCharacteristics() {
- assertEquals(Spliterator.DISTINCT, StreamOpFlag.IS_DISTINCT);
- assertEquals(Spliterator.SORTED, StreamOpFlag.IS_SORTED);
- assertEquals(Spliterator.ORDERED, StreamOpFlag.IS_ORDERED);
- assertEquals(Spliterator.SIZED, StreamOpFlag.IS_SIZED);
-
- List<Integer> others = Arrays.asList(Spliterator.NONNULL, Spliterator.IMMUTABLE,
- Spliterator.CONCURRENT, Spliterator.SUBSIZED);
- for (int c : others) {
- assertNotEquals(c, StreamOpFlag.IS_SHORT_CIRCUIT);
- }
- }
-
- public void testSpliteratorCharacteristicsMask() {
- assertSpliteratorCharacteristicsMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
- assertSpliteratorCharacteristicsMask(StreamOpFlag.DISTINCT.clear(), 0);
-
- assertSpliteratorCharacteristicsMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
- assertSpliteratorCharacteristicsMask(StreamOpFlag.SORTED.clear(), 0);
-
- assertSpliteratorCharacteristicsMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
- assertSpliteratorCharacteristicsMask(StreamOpFlag.ORDERED.clear(), 0);
-
- assertSpliteratorCharacteristicsMask(StreamOpFlag.SIZED.set(), StreamOpFlag.IS_SIZED);
- assertSpliteratorCharacteristicsMask(StreamOpFlag.SIZED.clear(), 0);
-
- assertSpliteratorCharacteristicsMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
- assertSpliteratorCharacteristicsMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
- }
-
- private void assertSpliteratorCharacteristicsMask(int actual, int expected) {
- assertEquals(StreamOpFlag.fromCharacteristics(actual), expected);
- }
-
- public void testSpliteratorSorted() {
- class SortedEmptySpliterator implements Spliterator<Object> {
- final Comparator<Object> c;
-
- SortedEmptySpliterator(Comparator<Object> c) {
- this.c = c;
- }
-
- @Override
- public Spliterator<Object> trySplit() {
- return null;
- }
-
- @Override
- public boolean tryAdvance(Consumer<? super Object> action) {
- return false;
- }
-
- @Override
- public long estimateSize() {
- return Long.MAX_VALUE;
- }
-
- @Override
- public int characteristics() {
- return Spliterator.SORTED;
- }
-
- @Override
- public Comparator<? super Object> getComparator() {
- return c;
- }
- };
-
- {
- int flags = StreamOpFlag.fromCharacteristics(new SortedEmptySpliterator(null));
- assertEquals(flags, StreamOpFlag.IS_SORTED);
- }
-
- {
- int flags = StreamOpFlag.fromCharacteristics(new SortedEmptySpliterator((a, b) -> 0));
- assertEquals(flags, 0);
- }
- }
-}
--- a/jdk/test/java/util/stream/boottest/java/util/stream/StreamReuseTest.java Fri Nov 20 15:40:23 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,441 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream;
-
-import org.testng.annotations.Test;
-
-import java.util.function.Function;
-
-import static org.testng.Assert.fail;
-
-/**
- * StreamReuseTest
- *
- * @author Brian Goetz
- */
-@Test
-public class StreamReuseTest {
-
- private <T, U, E, S extends BaseStream<E, S>, D extends TestData<E, S>> void assertSecondFails(
- D data,
- Function<S, T> first,
- Function<S, U> second,
- Class<? extends Throwable> exception,
- String text) {
- S stream = data.stream();
- T fr = first.apply(stream);
- try {
- U sr = second.apply(stream);
- fail(text + " (seq)");
- }
- catch (Throwable e) {
- if (exception.isAssignableFrom(e.getClass())) {
- // Expected
- }
- else if (e instanceof Error)
- throw (Error) e;
- else if (e instanceof RuntimeException)
- throw (RuntimeException) e;
- else
- throw new AssertionError("Unexpected exception " + e.getClass(), e);
- }
-
- stream = data.parallelStream();
- fr = first.apply(stream);
- try {
- U sr = second.apply(stream);
- fail(text + " (par)");
- }
- catch (Throwable e) {
- if (exception.isAssignableFrom(e.getClass())) {
- // Expected
- }
- else if (e instanceof Error)
- throw (Error) e;
- else if (e instanceof RuntimeException)
- throw (RuntimeException) e;
- else
- throw new AssertionError("Unexpected exception " + e.getClass(), e);
- }
- }
-
- // Stream
-
- @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
- public void testTwoStreams(String name, TestData<Integer, Stream<Integer>> data) {
- assertSecondFails(data,
- (Stream<Integer> s) -> s.map(i -> i), (Stream<Integer> s) -> s.map(i -> i),
- IllegalStateException.class,
- "Stream map / map succeeded erroneously");
- assertSecondFails(data,
- Stream::distinct, (Stream<Integer> s) -> s.map(i -> i),
- IllegalStateException.class,
- "Stream distinct / map succeeded erroneously");
- assertSecondFails(data,
- (Stream<Integer> s) -> s.map(i -> i), Stream::distinct,
- IllegalStateException.class,
- "Stream map / distinct succeeded erroneously");
- assertSecondFails(data,
- Stream::distinct, Stream::distinct,
- IllegalStateException.class,
- "Stream distinct / distinct succeeded erroneously");
- }
-
- @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
- public void testTwoTerminals(String name, TestData<Integer, Stream<Integer>> data) {
- assertSecondFails(data,
- Stream::findFirst, Stream::findFirst,
- IllegalStateException.class,
- "Stream findFirst / findFirst succeeded erroneously");
- }
-
- @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
- public void testTerminalStream(String name, TestData<Integer, Stream<Integer>> data) {
- assertSecondFails(data,
- Stream::findFirst, (Stream<Integer> s) -> s.map(i -> i),
- IllegalStateException.class,
- "Stream findFirst / map succeeded erroneously");
- assertSecondFails(data,
- (Stream<Integer> s) -> s.map(i -> i), Stream::findFirst,
- IllegalStateException.class,
- "Stream map / findFirst succeeded erroneously");
- assertSecondFails(data,
- Stream::findFirst, Stream::distinct,
- IllegalStateException.class,
- "Stream findFirst / distinct succeeded erroneously");
- assertSecondFails(data,
- Stream::distinct, Stream::findFirst,
- IllegalStateException.class,
- "Stream distinct / findFirst succeeded erroneously");
- }
-
- @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
- public void testTwoIterators(String name, TestData<Integer, Stream<Integer>> data) {
- assertSecondFails(data,
- Stream::iterator, Stream::iterator,
- IllegalStateException.class,
- "Stream iterator / iterator succeeded erroneously");
- }
-
- @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
- public void testTerminalIterator(String name, TestData<Integer, Stream<Integer>> data) {
- assertSecondFails(data,
- Stream::iterator, Stream::findFirst,
- IllegalStateException.class,
- "Stream iterator / findFirst succeeded erroneously");
- assertSecondFails(data,
- Stream::findFirst, Stream::iterator,
- IllegalStateException.class,
- "Stream findFirst / iterator succeeded erroneously");
- }
-
- @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
- public void testStreamIterator(String name, TestData<Integer, Stream<Integer>> data) {
- assertSecondFails(data,
- Stream::iterator, (Stream<Integer> s) -> s.map(i -> i),
- IllegalStateException.class,
- "Stream iterator / map succeeded erroneously");
- assertSecondFails(data,
- (Stream<Integer> s) -> s.map(i -> i), Stream::iterator,
- IllegalStateException.class,
- "Stream map / iterator succeeded erroneously");
- assertSecondFails(data,
- Stream::iterator, Stream::distinct,
- IllegalStateException.class,
- "Stream iterator / distinct succeeded erroneously");
- assertSecondFails(data,
- Stream::distinct, Stream::iterator,
- IllegalStateException.class,
- "Stream distinct / iterator succeeded erroneously");
- }
-
- // IntStream
-
- @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
- public void testTwoStreams(String name, TestData.OfInt data) {
- assertSecondFails(data,
- (IntStream s) -> s.mapToObj(i -> i), (IntStream s) -> s.mapToObj(i -> i),
- IllegalStateException.class,
- "IntStream map / map succeeded erroneously");
- assertSecondFails(data,
- IntStream::distinct, (IntStream s) -> s.mapToObj(i -> i),
- IllegalStateException.class,
- "IntStream distinct / map succeeded erroneously");
- assertSecondFails(data,
- (IntStream s) -> s.mapToObj(i -> i), IntStream::distinct,
- IllegalStateException.class,
- "IntStream map / distinct succeeded erroneously");
- assertSecondFails(data,
- IntStream::distinct, IntStream::distinct,
- IllegalStateException.class,
- "IntStream distinct / distinct succeeded erroneously");
- }
-
- @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
- public void testTwoTerminals(String name, TestData.OfInt data) {
- assertSecondFails(data,
- IntStream::sum, IntStream::sum,
- IllegalStateException.class,
- "IntStream sum / sum succeeded erroneously");
- }
-
- @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
- public void testTerminalStream(String name, TestData.OfInt data) {
- assertSecondFails(data,
- IntStream::sum, (IntStream s) -> s.mapToObj(i -> i),
- IllegalStateException.class,
- "IntStream sum / map succeeded erroneously");
- assertSecondFails(data,
- (IntStream s) -> s.mapToObj(i -> i), IntStream::sum,
- IllegalStateException.class,
- "IntStream map / sum succeeded erroneously");
- assertSecondFails(data,
- IntStream::sum, IntStream::distinct,
- IllegalStateException.class,
- "IntStream sum / distinct succeeded erroneously");
- assertSecondFails(data,
- IntStream::distinct, IntStream::sum,
- IllegalStateException.class,
- "IntStream distinct / sum succeeded erroneously");
- }
-
- @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
- public void testTwoIterators(String name, TestData.OfInt data) {
- assertSecondFails(data,
- IntStream::iterator, IntStream::iterator,
- IllegalStateException.class,
- "IntStream iterator / iterator succeeded erroneously");
- }
-
- @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
- public void testTerminalIterator(String name, TestData.OfInt data) {
- assertSecondFails(data,
- IntStream::iterator, IntStream::sum,
- IllegalStateException.class,
- "IntStream iterator / sum succeeded erroneously");
- assertSecondFails(data,
- IntStream::sum, IntStream::iterator,
- IllegalStateException.class,
- "Stream sum / iterator succeeded erroneously");
- }
-
- @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
- public void testStreamIterator(String name, TestData.OfInt data) {
- assertSecondFails(data,
- IntStream::iterator, (IntStream s) -> s.mapToObj(i -> i),
- IllegalStateException.class,
- "IntStream iterator / map succeeded erroneously");
- assertSecondFails(data,
- (IntStream s) -> s.mapToObj(i -> i), IntStream::iterator,
- IllegalStateException.class,
- "IntStream map / iterator succeeded erroneously");
- assertSecondFails(data,
- IntStream::iterator, IntStream::distinct,
- IllegalStateException.class,
- "IntStream iterator / distinct succeeded erroneously");
- assertSecondFails(data,
- IntStream::distinct, IntStream::iterator,
- IllegalStateException.class,
- "IntStream distinct / iterator succeeded erroneously");
- }
-
- // LongStream
-
- @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
- public void testTwoStreams(String name, TestData.OfLong data) {
- assertSecondFails(data,
- (LongStream s) -> s.mapToObj(i -> i), (LongStream s) -> s.mapToObj(i -> i),
- IllegalStateException.class,
- "LongStream map / map succeeded erroneously");
- assertSecondFails(data,
- LongStream::distinct, (LongStream s) -> s.mapToObj(i -> i),
- IllegalStateException.class,
- "LongStream distinct / map succeeded erroneously");
- assertSecondFails(data,
- (LongStream s) -> s.mapToObj(i -> i), LongStream::distinct,
- IllegalStateException.class,
- "LongStream map / distinct succeeded erroneously");
- assertSecondFails(data,
- LongStream::distinct, LongStream::distinct,
- IllegalStateException.class,
- "LongStream distinct / distinct succeeded erroneously");
- }
-
- @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
- public void testTwoTerminals(String name, TestData.OfLong data) {
- assertSecondFails(data,
- LongStream::sum, LongStream::sum,
- IllegalStateException.class,
- "LongStream sum / sum succeeded erroneously");
- }
-
- @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
- public void testTerminalStream(String name, TestData.OfLong data) {
- assertSecondFails(data,
- LongStream::sum, (LongStream s) -> s.mapToObj(i -> i),
- IllegalStateException.class,
- "LongStream sum / map succeeded erroneously");
- assertSecondFails(data,
- (LongStream s) -> s.mapToObj(i -> i), LongStream::sum,
- IllegalStateException.class,
- "LongStream map / sum succeeded erroneously");
- assertSecondFails(data,
- LongStream::sum, LongStream::distinct,
- IllegalStateException.class,
- "LongStream sum / distinct succeeded erroneously");
- assertSecondFails(data,
- LongStream::distinct, LongStream::sum,
- IllegalStateException.class,
- "LongStream distinct / sum succeeded erroneously");
- }
-
- @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
- public void testTwoIterators(String name, TestData.OfLong data) {
- assertSecondFails(data,
- LongStream::iterator, LongStream::iterator,
- IllegalStateException.class,
- "LongStream iterator / iterator succeeded erroneously");
- }
-
- @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
- public void testTerminalIterator(String name, TestData.OfLong data) {
- assertSecondFails(data,
- LongStream::iterator, LongStream::sum,
- IllegalStateException.class,
- "LongStream iterator / sum succeeded erroneously");
- assertSecondFails(data,
- LongStream::sum, LongStream::iterator,
- IllegalStateException.class,
- "Stream sum / iterator succeeded erroneously");
- }
-
- @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
- public void testStreamIterator(String name, TestData.OfLong data) {
- assertSecondFails(data,
- LongStream::iterator, (LongStream s) -> s.mapToObj(i -> i),
- IllegalStateException.class,
- "LongStream iterator / map succeeded erroneously");
- assertSecondFails(data,
- (LongStream s) -> s.mapToObj(i -> i), LongStream::iterator,
- IllegalStateException.class,
- "LongStream map / iterator succeeded erroneously");
- assertSecondFails(data,
- LongStream::iterator, LongStream::distinct,
- IllegalStateException.class,
- "LongStream iterator / distinct succeeded erroneously");
- assertSecondFails(data,
- LongStream::distinct, LongStream::iterator,
- IllegalStateException.class,
- "LongStream distinct / iterator succeeded erroneously");
- }
-
- // DoubleStream
-
- @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
- public void testTwoStreams(String name, TestData.OfDouble data) {
- assertSecondFails(data,
- (DoubleStream s) -> s.mapToObj(i -> i), (DoubleStream s) -> s.mapToObj(i -> i),
- IllegalStateException.class,
- "DoubleStream map / map succeeded erroneously");
- assertSecondFails(data,
- DoubleStream::distinct, (DoubleStream s) -> s.mapToObj(i -> i),
- IllegalStateException.class,
- "DoubleStream distinct / map succeeded erroneously");
- assertSecondFails(data,
- (DoubleStream s) -> s.mapToObj(i -> i), DoubleStream::distinct,
- IllegalStateException.class,
- "DoubleStream map / distinct succeeded erroneously");
- assertSecondFails(data,
- DoubleStream::distinct, DoubleStream::distinct,
- IllegalStateException.class,
- "DoubleStream distinct / distinct succeeded erroneously");
- }
-
- @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
- public void testTwoTerminals(String name, TestData.OfDouble data) {
- assertSecondFails(data,
- DoubleStream::sum, DoubleStream::sum,
- IllegalStateException.class,
- "DoubleStream sum / sum succeeded erroneously");
- }
-
- @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
- public void testTerminalStream(String name, TestData.OfDouble data) {
- assertSecondFails(data,
- DoubleStream::sum, (DoubleStream s) -> s.mapToObj(i -> i),
- IllegalStateException.class,
- "DoubleStream sum / map succeeded erroneously");
- assertSecondFails(data,
- (DoubleStream s) -> s.mapToObj(i -> i), DoubleStream::sum,
- IllegalStateException.class,
- "DoubleStream map / sum succeeded erroneously");
- assertSecondFails(data,
- DoubleStream::sum, DoubleStream::distinct,
- IllegalStateException.class,
- "DoubleStream sum / distinct succeeded erroneously");
- assertSecondFails(data,
- DoubleStream::distinct, DoubleStream::sum,
- IllegalStateException.class,
- "DoubleStream distinct / sum succeeded erroneously");
- }
-
- @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
- public void testTwoIterators(String name, TestData.OfDouble data) {
- assertSecondFails(data,
- DoubleStream::iterator, DoubleStream::iterator,
- IllegalStateException.class,
- "DoubleStream iterator / iterator succeeded erroneously");
- }
-
- @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
- public void testTerminalIterator(String name, TestData.OfDouble data) {
- assertSecondFails(data,
- DoubleStream::iterator, DoubleStream::sum,
- IllegalStateException.class,
- "DoubleStream iterator / sum succeeded erroneously");
- assertSecondFails(data,
- DoubleStream::sum, DoubleStream::iterator,
- IllegalStateException.class,
- "Stream sum / iterator succeeded erroneously");
- }
-
- @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
- public void testStreamIterator(String name, TestData.OfDouble data) {
- assertSecondFails(data,
- DoubleStream::iterator, (DoubleStream s) -> s.mapToObj(i -> i),
- IllegalStateException.class,
- "DoubleStream iterator / map succeeded erroneously");
- assertSecondFails(data,
- (DoubleStream s) -> s.mapToObj(i -> i), DoubleStream::iterator,
- IllegalStateException.class,
- "DoubleStream map / iterator succeeded erroneously");
- assertSecondFails(data,
- DoubleStream::iterator, DoubleStream::distinct,
- IllegalStateException.class,
- "DoubleStream iterator / distinct succeeded erroneously");
- assertSecondFails(data,
- DoubleStream::distinct, DoubleStream::iterator,
- IllegalStateException.class,
- "DoubleStream distinct / iterator succeeded erroneously");
- }
-}
--- a/jdk/test/java/util/stream/test/TEST.properties Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/java/util/stream/test/TEST.properties Wed Jul 05 21:02:29 2017 +0200
@@ -2,7 +2,7 @@
TestNG.dirs = .
-lib.dirs = /java/util/stream/bootlib
+lib.dirs = /java/util/stream/bootlib/java.base
# Tests that must run in othervm mode
othervm.dirs= /java/util/stream
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/LookAndFeel/8138881/TestOSVersion.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8138881
+ * @summary typo in OSInfo.java
+ * @modules java.desktop/sun.awt
+ * @requires (os.family == "windows")
+ * @run main TestOSVersion
+ */
+
+import sun.awt.OSInfo;
+
+public class TestOSVersion {
+
+ private static final String WIN_VISTA_VERSION = "6.0";
+
+ public static void main(String[] arg) {
+
+ String oSVersion = System.getProperty("os.version");
+ if (WIN_VISTA_VERSION.equals(oSVersion)) {
+ if (OSInfo.getWindowsVersion().toString().equals("6.1") ) {
+ throw new RuntimeException("Incorrect Windows VISTA OS version "
+ + "in OSInfo");
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/plaf/metal/MetalUtils/bug6190373.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+import java.util.concurrent.CyclicBarrier;
+
+import javax.swing.JButton;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+
+import sun.awt.AppContext;
+import sun.awt.SunToolkit;
+
+import static javax.swing.UIManager.getInstalledLookAndFeels;
+
+/**
+ * @test
+ * @bug 6190373
+ * @summary Tests 6190373
+ * @author Scott Violet
+ * @modules java.desktop/sun.awt
+ */
+public final class bug6190373 {
+
+ private static AppContext app1;
+ private static AppContext app2;
+ private static final int LOOP_COUNT = 10000;
+ private static final CyclicBarrier barrier = new CyclicBarrier(2);
+
+ public static void main(final String[] args) throws Exception {
+ final Thread t1 = new Thread(new ThreadGroup("firstGroup"), () -> {
+ app1 = SunToolkit.createNewAppContext();
+ test(true);
+ });
+ final Thread t2 = new Thread(new ThreadGroup("secondGroup"), () -> {
+ app2 = SunToolkit.createNewAppContext();
+ test(false);
+ });
+
+ t1.start();
+ t2.start();
+ t1.join();
+ t2.join();
+ app1.dispose();
+ app2.dispose();
+ }
+
+ private static void test(final boolean lock) {
+ for (final UIManager.LookAndFeelInfo laf : getInstalledLookAndFeels()) {
+ try {
+ SwingUtilities.invokeAndWait(() -> setLookAndFeel(laf));
+ barrier.await();
+ SwingUtilities.invokeAndWait(() -> slam(lock));
+ barrier.await();
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private static void slam(final boolean lock) {
+ JButton button = new JButton("HI");
+ button.setSize(100, 100);
+ BufferedImage image = new BufferedImage(100, 100,
+ BufferedImage.TYPE_INT_RGB);
+ for (int i = 0; i < LOOP_COUNT; i++) {
+ Graphics g = image.getGraphics();
+ if (lock) {
+ synchronized (button.getTreeLock()) {
+ button.paint(g);
+ }
+ } else {
+ button.paint(g);
+ }
+ g.dispose();
+ }
+ }
+
+ private static void setLookAndFeel(final UIManager.LookAndFeelInfo laf) {
+ try {
+ UIManager.setLookAndFeel(laf.getClassName());
+ System.out.println("LookAndFeel: " + laf.getClassName());
+ } catch (ClassNotFoundException | InstantiationException |
+ UnsupportedLookAndFeelException | IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/plaf/nimbus/8041642/ScrollBarThumbVisibleTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ @bug 8134828
+ @summary Scrollbar thumb disappears with Nimbus L&F
+ @author Semyon Sadetsky
+*/
+
+import javax.swing.*;
+import java.awt.*;
+
+public class ScrollBarThumbVisibleTest
+{
+ private static JFrame frame;
+ private static Point point;
+ private static JScrollBar bar;
+
+ public static void main(String[] args) throws Exception {
+ for (UIManager.LookAndFeelInfo info : UIManager
+ .getInstalledLookAndFeels()) {
+ if ("Nimbus".equals(info.getName())) {
+ try {
+ UIManager.setLookAndFeel(info.getClassName());
+ } catch (Exception ex) {
+ }
+ break;
+ }
+ }
+ try {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ frame = new JFrame();
+ frame.setUndecorated(true);
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ setup(frame);
+ }
+ });
+ final Robot robot = new Robot();
+ robot.delay(200);
+ robot.waitForIdle();
+ SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ point = bar.getLocationOnScreen();
+ }
+ });
+ Color color1 = robot.getPixelColor(point.x + 48, point.y + 55);
+ Color color2 = robot.getPixelColor(point.x + 48, point.y + 125);
+ System.out.println(color1);
+ System.out.println(color2);
+ if (color1.equals(color2)) {
+ throw new RuntimeException("Thump is not visible");
+ }
+ } finally {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ frame.dispose();
+ }
+ });
+ }
+ System.out.println("ok");
+ }
+
+ static void setup(JFrame frame) {
+ bar = new JScrollBar(Adjustable.VERTICAL, 500, 0, 0, 1000);
+ frame.getContentPane().add(bar);
+ frame.setSize(50, 250);
+ frame.setLocation(100, 100);
+ frame.setVisible(true);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/security/jarsigner/Function.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8056174
+ * @summary test the functions of JarSigner API
+ * @modules java.base/sun.security.tools.keytool
+ * jdk.jartool
+ */
+
+import jdk.security.jarsigner.JarSigner;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.KeyStore;
+import java.security.MessageDigest;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+public class Function {
+ public static void main(String[] args) throws Exception {
+
+ try (FileOutputStream fout =new FileOutputStream("src.zip");
+ ZipOutputStream zout = new ZipOutputStream(fout)) {
+ zout.putNextEntry(new ZipEntry("x"));
+ zout.write(new byte[10]);
+ zout.closeEntry();
+ }
+
+ sun.security.tools.keytool.Main.main(
+ ("-storetype jks -keystore ks -storepass changeit" +
+ " -keypass changeit -dname" +
+ " CN=RSA -alias r -genkeypair -keyalg rsa").split(" "));
+
+ KeyStore ks = KeyStore.getInstance("JKS");
+ ks.load(new FileInputStream("ks"), "changeit".toCharArray());
+ PrivateKey key = (PrivateKey)ks.getKey("r", "changeit".toCharArray());
+ Certificate cert = ks.getCertificate("r");
+ JarSigner.Builder jsb = new JarSigner.Builder(key,
+ CertificateFactory.getInstance("X.509").generateCertPath(
+ Collections.singletonList(cert)));
+
+ jsb.digestAlgorithm("SHA1");
+ jsb.signatureAlgorithm("SHA1withRSA");
+
+ AtomicInteger counter = new AtomicInteger(0);
+ StringBuilder sb = new StringBuilder();
+ jsb.eventHandler(
+ (a, f)->{
+ counter.incrementAndGet();
+ sb.append(a).append(' ').append(f).append('\n');
+ });
+
+ OutputStream blackHole = new OutputStream() {
+ @Override
+ public void write(int b) throws IOException { }
+ };
+
+ try (ZipFile src = new ZipFile("src.zip")) {
+ jsb.build().sign(src, blackHole);
+ }
+
+ if (counter.get() != 4) {
+ throw new Exception("Event number is " + counter.get()
+ + ":\n" + sb.toString());
+ }
+
+ // Provider test.
+ Provider p = new MyProvider();
+ jsb.digestAlgorithm("Five", p);
+ jsb.signatureAlgorithm("SHA1WithRSA", p);
+ try (ZipFile src = new ZipFile("src.zip");
+ FileOutputStream out = new FileOutputStream("out.jar")) {
+ jsb.build().sign(src, out);
+ }
+
+ try (JarFile signed = new JarFile("out.jar")) {
+ Manifest man = signed.getManifest();
+ assertTrue(man.getAttributes("x").getValue("Five-Digest").equals("FAKE"));
+
+ Manifest sf = new Manifest(signed.getInputStream(
+ signed.getJarEntry("META-INF/SIGNER.SF")));
+ assertTrue(sf.getMainAttributes().getValue("Five-Digest-Manifest")
+ .equals("FAKE"));
+ assertTrue(sf.getAttributes("x").getValue("Five-Digest").equals("FAKE"));
+
+ try (InputStream sig = signed.getInputStream(
+ signed.getJarEntry("META-INF/SIGNER.RSA"))) {
+ byte[] data = sig.readAllBytes();
+ assertTrue(Arrays.equals(
+ Arrays.copyOfRange(data, data.length-8, data.length),
+ "FAKEFAKE".getBytes()));
+ }
+ }
+ }
+
+ private static void assertTrue(boolean v) {
+ if (!v) {
+ throw new AssertionError();
+ }
+ }
+
+ public static class MyProvider extends Provider {
+ MyProvider() {
+ super("MY", 1.0d, null);
+ put("MessageDigest.Five", Five.class.getName());
+ put("Signature.SHA1WithRSA", SHA1WithRSA.class.getName());
+ }
+ }
+
+ // "Five" is a MessageDigest always returns the same value
+ public static class Five extends MessageDigest {
+ static final byte[] dig = {0x14, 0x02, (byte)0x84}; //base64 -> FAKE
+ public Five() { super("Five"); }
+ protected void engineUpdate(byte input) { }
+ protected void engineUpdate(byte[] input, int offset, int len) { }
+ protected byte[] engineDigest() { return dig; }
+ protected void engineReset() { }
+ }
+
+ // This fake "SHA1withRSA" is a Signature always returns the same value.
+ // An existing name must be used otherwise PKCS7 does not which OID to use.
+ public static class SHA1WithRSA extends Signature {
+ static final byte[] sig = "FAKEFAKE".getBytes();
+ public SHA1WithRSA() { super("SHA1WithRSA"); }
+ protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException { }
+ protected void engineInitSign(PrivateKey privateKey)
+ throws InvalidKeyException { }
+ protected void engineUpdate(byte b) throws SignatureException { }
+ protected void engineUpdate(byte[] b, int off, int len)
+ throws SignatureException { }
+ protected byte[] engineSign() throws SignatureException { return sig; }
+ protected boolean engineVerify(byte[] sigBytes)
+ throws SignatureException {
+ return Arrays.equals(sigBytes, sig);
+ }
+ protected void engineSetParameter(String param, Object value)
+ throws InvalidParameterException { }
+ protected Object engineGetParameter(String param)
+ throws InvalidParameterException { return null; }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/security/jarsigner/Spec.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8056174
+ * @summary Make sure JarSigner impl conforms to spec
+ * @library /lib/testlibrary
+ * @modules java.base/sun.security.tools.keytool
+ * java.base/sun.security.provider.certpath
+ * jdk.jartool
+ */
+
+import com.sun.jarsigner.ContentSigner;
+import com.sun.jarsigner.ContentSignerParameters;
+import jdk.security.jarsigner.JarSigner;
+import jdk.testlibrary.JarUtils;
+import sun.security.provider.certpath.X509CertPath;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.security.*;
+import java.security.cert.CertPath;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.function.BiConsumer;
+
+public class Spec {
+
+ public static void main(String[] args) throws Exception {
+
+ // Prepares raw file
+ Files.write(Paths.get("a"), "a".getBytes());
+
+ // Pack
+ JarUtils.createJar("a.jar", "a");
+
+ // Prepare a keystore
+ sun.security.tools.keytool.Main.main(
+ ("-keystore ks -storepass changeit -keypass changeit -dname" +
+ " CN=RSA -alias r -genkeypair -keyalg rsa").split(" "));
+ sun.security.tools.keytool.Main.main(
+ ("-keystore ks -storepass changeit -keypass changeit -dname" +
+ " CN=DSA -alias d -genkeypair -keyalg dsa").split(" "));
+
+ char[] pass = "changeit".toCharArray();
+
+ KeyStore ks = KeyStore.getInstance(
+ new File("ks"), pass);
+ PrivateKey pkr = (PrivateKey)ks.getKey("r", pass);
+ PrivateKey pkd = (PrivateKey)ks.getKey("d", pass);
+ CertPath cp = CertificateFactory.getInstance("X.509")
+ .generateCertPath(Arrays.asList(ks.getCertificateChain("r")));
+
+ Provider sun = Security.getProvider("SUN");
+
+ // throws
+ npe(()->new JarSigner.Builder(null));
+ npe(()->new JarSigner.Builder(null, cp));
+ iae(()->new JarSigner.Builder(
+ pkr, new X509CertPath(Collections.emptyList())));
+ iae(()->new JarSigner.Builder(pkd, cp)); // unmatched certs alg
+
+ JarSigner.Builder b1 = new JarSigner.Builder(pkr, cp);
+
+ npe(()->b1.digestAlgorithm(null));
+ nsae(()->b1.digestAlgorithm("HAHA"));
+ b1.digestAlgorithm("SHA-256");
+
+ npe(()->b1.digestAlgorithm("SHA-256", null));
+ npe(()->b1.digestAlgorithm(null, sun));
+ nsae(()->b1.digestAlgorithm("HAHA", sun));
+ b1.digestAlgorithm("SHA-256", sun);
+
+ npe(()->b1.signatureAlgorithm(null));
+ nsae(()->b1.signatureAlgorithm("HAHAwithHEHE"));
+ iae(()->b1.signatureAlgorithm("SHA256withECDSA"));
+
+ npe(()->b1.signatureAlgorithm(null, sun));
+ npe(()->b1.signatureAlgorithm("SHA256withRSA", null));
+ nsae(()->b1.signatureAlgorithm("HAHAwithHEHE", sun));
+ iae(()->b1.signatureAlgorithm("SHA256withDSA", sun));
+
+ npe(()->b1.tsa(null));
+
+ npe(()->b1.signerName(null));
+ iae(()->b1.signerName(""));
+ iae(()->b1.signerName("123456789"));
+ iae(()->b1.signerName("a+b"));
+
+ npe(()->b1.setProperty(null, ""));
+ uoe(()->b1.setProperty("what", ""));
+ npe(()->b1.setProperty("tsadigestalg", null));
+ iae(()->b1.setProperty("tsadigestalg", "HAHA"));
+ npe(()->b1.setProperty("tsapolicyid", null));
+ npe(()->b1.setProperty("internalsf", null));
+ iae(()->b1.setProperty("internalsf", "Hello"));
+ npe(()->b1.setProperty("sectionsonly", null));
+ iae(()->b1.setProperty("sectionsonly", "OK"));
+ npe(()->b1.setProperty("altsigner", null));
+ npe(()->b1.eventHandler(null));
+
+ // default values
+ JarSigner.Builder b2 = new JarSigner.Builder(pkr, cp);
+ JarSigner js2 = b2.build();
+
+ assertTrue(js2.getDigestAlgorithm().equals(
+ JarSigner.Builder.getDefaultDigestAlgorithm()));
+ assertTrue(js2.getSignatureAlgorithm().equals(
+ JarSigner.Builder.getDefaultSignatureAlgorithm(pkr)));
+ assertTrue(js2.getTsa() == null);
+ assertTrue(js2.getSignerName().equals("SIGNER"));
+ assertTrue(js2.getProperty("tsadigestalg").equals(
+ JarSigner.Builder.getDefaultDigestAlgorithm()));
+ assertTrue(js2.getProperty("tsapolicyid") == null);
+ assertTrue(js2.getProperty("internalsf").equals("false"));
+ assertTrue(js2.getProperty("sectionsonly").equals("false"));
+ assertTrue(js2.getProperty("altsigner") == null);
+ uoe(()->js2.getProperty("invalid"));
+
+ // default values
+ BiConsumer<String,String> myeh = (a,s)->{};
+ URI tsa = new URI("https://tsa.com");
+
+ JarSigner.Builder b3 = new JarSigner.Builder(pkr, cp)
+ .digestAlgorithm("SHA-1")
+ .signatureAlgorithm("SHA1withRSA")
+ .signerName("Duke")
+ .tsa(tsa)
+ .setProperty("tsadigestalg", "SHA-512")
+ .setProperty("tsapolicyid", "1.2.3.4")
+ .setProperty("internalsf", "true")
+ .setProperty("sectionsonly", "true")
+ .setProperty("altsigner", "MyContentSigner")
+ .eventHandler(myeh);
+ JarSigner js3 = b3.build();
+
+ assertTrue(js3.getDigestAlgorithm().equals("SHA-1"));
+ assertTrue(js3.getSignatureAlgorithm().equals("SHA1withRSA"));
+ assertTrue(js3.getTsa().equals(tsa));
+ assertTrue(js3.getSignerName().equals("DUKE"));
+ assertTrue(js3.getProperty("tsadigestalg").equals("SHA-512"));
+ assertTrue(js3.getProperty("tsapolicyid").equals("1.2.3.4"));
+ assertTrue(js3.getProperty("internalsf").equals("true"));
+ assertTrue(js3.getProperty("sectionsonly").equals("true"));
+ assertTrue(js3.getProperty("altsigner").equals("MyContentSigner"));
+ assertTrue(js3.getProperty("altsignerpath") == null);
+
+ assertTrue(JarSigner.Builder.getDefaultDigestAlgorithm().equals("SHA-256"));
+
+ // Calculating large DSA and RSA keys are too slow.
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ kpg.initialize(1024);
+ assertTrue(JarSigner.Builder
+ .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate())
+ .equals("SHA256withRSA"));
+
+ kpg = KeyPairGenerator.getInstance("DSA");
+ kpg.initialize(1024);
+ assertTrue(JarSigner.Builder
+ .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate())
+ .equals("SHA256withDSA"));
+
+ kpg = KeyPairGenerator.getInstance("EC");
+ kpg.initialize(192);
+ assertTrue(JarSigner.Builder
+ .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate())
+ .equals("SHA256withECDSA"));
+ kpg.initialize(384);
+ assertTrue(JarSigner.Builder
+ .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate())
+ .equals("SHA384withECDSA"));
+ kpg.initialize(571);
+ assertTrue(JarSigner.Builder
+ .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate())
+ .equals("SHA512withECDSA"));
+ }
+
+ interface RunnableWithException {
+ void run() throws Exception;
+ }
+
+ static void uoe(RunnableWithException r) throws Exception {
+ checkException(r, UnsupportedOperationException.class);
+ }
+
+ static void nsae(RunnableWithException r) throws Exception {
+ checkException(r, NoSuchAlgorithmException.class);
+ }
+
+ static void npe(RunnableWithException r) throws Exception {
+ checkException(r, NullPointerException.class);
+ }
+
+ static void iae(RunnableWithException r) throws Exception {
+ checkException(r, IllegalArgumentException.class);
+ }
+
+ static void checkException(RunnableWithException r, Class ex)
+ throws Exception {
+ try {
+ r.run();
+ } catch (Exception e) {
+ if (ex.isAssignableFrom(e.getClass())) {
+ return;
+ }
+ throw e;
+ }
+ throw new Exception("No exception thrown");
+ }
+
+ static void assertTrue(boolean x) throws Exception {
+ if (!x) throw new Exception("Not true");
+ }
+
+ static class MyContentSigner extends ContentSigner {
+ @Override
+ public byte[] generateSignedData(
+ ContentSignerParameters parameters,
+ boolean omitContent,
+ boolean applyTimestamp) throws NoSuchAlgorithmException,
+ CertificateException, IOException {
+ return new byte[0];
+ }
+ }
+}
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java Wed Jul 05 21:02:29 2017 +0200
@@ -38,14 +38,14 @@
private final OutputBuffer output;
private final String stdout;
private final String stderr;
- private final int exitValue;
+ private final int exitValue; // useless now. output contains exit value.
/**
* Create an OutputAnalyzer, a utility class for verifying output and exit
* value from a Process.
* <p>
* OutputAnalyzer should never be instantiated directly -
- * use {@linkplain ProcessTools#executeProcess(p)} instead
+ * use {@linkplain ProcessTools#executeProcess(ProcessBuilder)} instead
*
* @param process
* Process to analyze
@@ -93,13 +93,14 @@
* @throws RuntimeException
* If the string was not found
*/
- public void shouldContain(String expectedString) {
+ public OutputAnalyzer shouldContain(String expectedString) {
if (!getStdout().contains(expectedString)
&& !getStderr().contains(expectedString)) {
reportDiagnosticSummary();
throw new RuntimeException("'" + expectedString
+ "' missing from stdout/stderr \n");
}
+ return this;
}
/**
@@ -110,12 +111,13 @@
* @throws RuntimeException
* If the string was not found
*/
- public void stdoutShouldContain(String expectedString) {
+ public OutputAnalyzer stdoutShouldContain(String expectedString) {
if (!getStdout().contains(expectedString)) {
reportDiagnosticSummary();
throw new RuntimeException("'" + expectedString
+ "' missing from stdout \n");
}
+ return this;
}
/**
@@ -126,24 +128,25 @@
* @throws RuntimeException
* If the string was not found
*/
- public void stderrShouldContain(String expectedString) {
+ public OutputAnalyzer stderrShouldContain(String expectedString) {
if (!getStderr().contains(expectedString)) {
reportDiagnosticSummary();
throw new RuntimeException("'" + expectedString
+ "' missing from stderr \n");
}
+ return this;
}
/**
* Verify that the stdout and stderr contents of output buffer does not
* contain the string
*
- * @param expectedString
+ * @param notExpectedString
* String that the buffer should not contain
* @throws RuntimeException
* If the string was found
*/
- public void shouldNotContain(String notExpectedString) {
+ public OutputAnalyzer shouldNotContain(String notExpectedString) {
if (getStdout().contains(notExpectedString)) {
reportDiagnosticSummary();
throw new RuntimeException("'" + notExpectedString
@@ -154,40 +157,43 @@
throw new RuntimeException("'" + notExpectedString
+ "' found in stderr \n");
}
+ return this;
}
/**
* Verify that the stdout contents of output buffer does not contain the
* string
*
- * @param expectedString
+ * @param notExpectedString
* String that the buffer should not contain
* @throws RuntimeException
* If the string was found
*/
- public void stdoutShouldNotContain(String notExpectedString) {
+ public OutputAnalyzer stdoutShouldNotContain(String notExpectedString) {
if (getStdout().contains(notExpectedString)) {
reportDiagnosticSummary();
throw new RuntimeException("'" + notExpectedString
+ "' found in stdout \n");
}
+ return this;
}
/**
* Verify that the stderr contents of output buffer does not contain the
* string
*
- * @param expectedString
+ * @param notExpectedString
* String that the buffer should not contain
* @throws RuntimeException
* If the string was found
*/
- public void stderrShouldNotContain(String notExpectedString) {
+ public OutputAnalyzer stderrShouldNotContain(String notExpectedString) {
if (getStderr().contains(notExpectedString)) {
reportDiagnosticSummary();
throw new RuntimeException("'" + notExpectedString
+ "' found in stderr \n");
}
+ return this;
}
/**
@@ -198,7 +204,7 @@
* @throws RuntimeException
* If the pattern was not found
*/
- public void shouldMatch(String pattern) {
+ public OutputAnalyzer shouldMatch(String pattern) {
Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE)
.matcher(getStdout());
Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE)
@@ -208,6 +214,7 @@
throw new RuntimeException("'" + pattern
+ "' missing from stdout/stderr \n");
}
+ return this;
}
/**
@@ -217,7 +224,7 @@
* @throws RuntimeException
* If the pattern was not found
*/
- public void stdoutShouldMatch(String pattern) {
+ public OutputAnalyzer stdoutShouldMatch(String pattern) {
Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(
getStdout());
if (!matcher.find()) {
@@ -225,6 +232,7 @@
throw new RuntimeException("'" + pattern
+ "' missing from stdout \n");
}
+ return this;
}
/**
@@ -234,7 +242,7 @@
* @throws RuntimeException
* If the pattern was not found
*/
- public void stderrShouldMatch(String pattern) {
+ public OutputAnalyzer stderrShouldMatch(String pattern) {
Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(
getStderr());
if (!matcher.find()) {
@@ -242,6 +250,7 @@
throw new RuntimeException("'" + pattern
+ "' missing from stderr \n");
}
+ return this;
}
/**
@@ -252,7 +261,7 @@
* @throws RuntimeException
* If the pattern was found
*/
- public void shouldNotMatch(String pattern) {
+ public OutputAnalyzer shouldNotMatch(String pattern) {
Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(
getStdout());
if (matcher.find()) {
@@ -266,6 +275,7 @@
throw new RuntimeException("'" + pattern + "' found in stderr: '"
+ matcher.group() + "' \n");
}
+ return this;
}
/**
@@ -276,13 +286,14 @@
* @throws RuntimeException
* If the pattern was found
*/
- public void stdoutShouldNotMatch(String pattern) {
+ public OutputAnalyzer stdoutShouldNotMatch(String pattern) {
Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(
getStdout());
if (matcher.find()) {
reportDiagnosticSummary();
throw new RuntimeException("'" + pattern + "' found in stdout \n");
}
+ return this;
}
/**
@@ -293,13 +304,14 @@
* @throws RuntimeException
* If the pattern was found
*/
- public void stderrShouldNotMatch(String pattern) {
+ public OutputAnalyzer stderrShouldNotMatch(String pattern) {
Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(
getStderr());
if (matcher.find()) {
reportDiagnosticSummary();
throw new RuntimeException("'" + pattern + "' found in stderr \n");
}
+ return this;
}
/**
@@ -347,12 +359,13 @@
* If the exit value from the process did not match the expected
* value
*/
- public void shouldHaveExitValue(int expectedExitValue) {
+ public OutputAnalyzer shouldHaveExitValue(int expectedExitValue) {
if (getExitValue() != expectedExitValue) {
reportDiagnosticSummary();
throw new RuntimeException("Expected to get exit value of ["
+ expectedExitValue + "]\n");
}
+ return this;
}
/**
@@ -360,11 +373,12 @@
* - standard input produced by the process under test - standard output -
* exit code Note: the command line is printed by the ProcessTools
*/
- private void reportDiagnosticSummary() {
+ private OutputAnalyzer reportDiagnosticSummary() {
String msg = " stdout: [" + getStdout() + "];\n" + " stderr: [" + getStderr()
+ "]\n" + " exitValue = " + getExitValue() + "\n";
System.err.println(msg);
+ return this;
}
/**
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java Wed Jul 05 21:02:29 2017 +0200
@@ -365,11 +365,31 @@
* @return The {@linkplain OutputAnalyzer} instance wrapping the process.
*/
public static OutputAnalyzer executeProcess(ProcessBuilder pb) throws Exception {
+ return executeProcess(pb, null);
+ }
+
+ /**
+ * Executes a process, pipe some text into its STDIN, waits for it
+ * to finish and returns the process output. The process will have exited
+ * before this method returns.
+ * @param pb The ProcessBuilder to execute.
+ * @param input The text to pipe into STDIN. Can be null.
+ * @return The {@linkplain OutputAnalyzer} instance wrapping the process.
+ */
+ public static OutputAnalyzer executeProcess(ProcessBuilder pb, String input)
+ throws Exception {
OutputAnalyzer output = null;
Process p = null;
boolean failed = false;
try {
p = pb.start();
+ if (input != null) {
+ try (OutputStream os = p.getOutputStream();
+ PrintStream ps = new PrintStream(os)) {
+ ps.print(input);
+ ps.flush();
+ }
+ }
output = new OutputAnalyzer(p);
p.waitFor();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/invoke/util/WrapperTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test.sun.invoke.util;
+
+import sun.invoke.util.ValueConversions;
+import sun.invoke.util.Wrapper;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.MethodHandle;
+import java.io.Serializable;
+import java.util.Arrays;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/* @test
+ * @summary unit tests to assert Wrapper zero identities and conversion behave correctly
+ * @modules java.base/sun.invoke.util
+ * @compile -XDignore.symbol.file WrapperTest.java
+ * @run junit test.sun.invoke.util.WrapperTest
+ */
+public class WrapperTest {
+
+ @Test
+ public void testShortZeroConversion() throws Throwable {
+ MethodHandle h1 = MethodHandles.constant(Short.class, (short)42);
+ MethodHandle h2 = h1.asType(MethodType.methodType(void.class)); // drop 42
+ MethodHandle h3 = h2.asType(MethodType.methodType(short.class)); // add 0
+ MethodHandle h4 = h3.asType(MethodType.methodType(Object.class)); // box
+
+ Object x = h4.invokeExact();
+ assertEquals(x, (short)0);
+ assertTrue(x == Short.valueOf((short)0));
+ assertTrue(x == Wrapper.SHORT.zero());
+ }
+
+ @Test
+ public void testIntZeroConversion() throws Throwable {
+ MethodHandle h1 = MethodHandles.constant(Integer.class, 42);
+ MethodHandle h2 = h1.asType(MethodType.methodType(void.class)); // drop 42
+ MethodHandle h3 = h2.asType(MethodType.methodType(int.class)); // add 0
+ MethodHandle h4 = h3.asType(MethodType.methodType(Object.class)); // box
+
+ Object x = h4.invokeExact();
+ assertEquals(x, 0);
+ assertTrue(x == Integer.valueOf(0));
+ assertTrue(x == Wrapper.INT.zero());
+ }
+
+ @Test
+ public void testLongZeroConversion() throws Throwable {
+ MethodHandle h1 = MethodHandles.constant(Long.class, 42L);
+ MethodHandle h2 = h1.asType(MethodType.methodType(void.class)); // drop 42
+ MethodHandle h3 = h2.asType(MethodType.methodType(long.class)); // add 0
+ MethodHandle h4 = h3.asType(MethodType.methodType(Object.class)); // box
+
+ Object x = h4.invokeExact();
+ assertEquals(x, 0L);
+ assertTrue(x == Long.valueOf(0));
+ assertTrue(x == Wrapper.LONG.zero());
+ }
+
+ @Test
+ public void testByteZeroConversion() throws Throwable {
+ MethodHandle h1 = MethodHandles.constant(Byte.class, (byte)42);
+ MethodHandle h2 = h1.asType(MethodType.methodType(void.class)); // drop 42
+ MethodHandle h3 = h2.asType(MethodType.methodType(byte.class)); // add 0
+ MethodHandle h4 = h3.asType(MethodType.methodType(Object.class)); // box
+
+ Object x = h4.invokeExact();
+ assertEquals(x, (byte)0);
+ assertTrue(x == Byte.valueOf((byte)0));
+ assertTrue(x == Wrapper.BYTE.zero());
+ }
+
+ @Test
+ public void testCharacterZeroConversion() throws Throwable {
+ MethodHandle h1 = MethodHandles.constant(Character.class, (char)42);
+ MethodHandle h2 = h1.asType(MethodType.methodType(void.class)); // drop 42
+ MethodHandle h3 = h2.asType(MethodType.methodType(char.class)); // add 0
+ MethodHandle h4 = h3.asType(MethodType.methodType(Object.class)); // box
+
+ Object x = h4.invokeExact();
+ assertEquals(x, (char)0);
+ assertTrue(x == Character.valueOf((char)0));
+ assertTrue(x == Wrapper.CHAR.zero());
+ }
+}
--- a/jdk/test/sun/jvmstat/monitor/MonitoredVm/TestPollingInterval.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/jvmstat/monitor/MonitoredVm/TestPollingInterval.java Wed Jul 05 21:02:29 2017 +0200
@@ -42,7 +42,7 @@
* @summary setInterval() for local MonitoredHost and local MonitoredVm
* @modules jdk.jvmstat/sun.jvmstat.monitor
* @library /lib/testlibrary
- * @library /../../test/lib/share/classes
+ * @library /test/lib/share/classes
* @build jdk.testlibrary.*
* @build jdk.test.lib.apps.*
* @run main TestPollingInterval
--- a/jdk/test/sun/security/mscapi/AccessKeyStore.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/AccessKeyStore.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,17 +36,6 @@
public static void main(String[] args) throws Exception {
- // Check if the provider is available
- try {
- Class.forName("sun.security.mscapi.SunMSCAPI");
-
- } catch (Exception e) {
- System.out.println(
- "The SunMSCAPI provider is not available on this platform: " +
- e);
- return;
- }
-
// Check that a security manager has been installed
if (System.getSecurityManager() == null) {
throw new Exception("A security manager has not been installed");
@@ -86,8 +75,8 @@
}
int i = 0;
- for (Enumeration e = keyStore.aliases(); e.hasMoreElements(); ) {
- String alias = (String) e.nextElement();
+ for (Enumeration<String> e = keyStore.aliases(); e.hasMoreElements(); ) {
+ String alias = e.nextElement();
displayEntry(keyStore, alias, i++);
}
}
--- a/jdk/test/sun/security/mscapi/AccessKeyStore.sh Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/AccessKeyStore.sh Wed Jul 05 21:02:29 2017 +0200
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
# @test
# @bug 6324295 6931562
+# @requires os.family == "windows"
# @run shell AccessKeyStore.sh
# @summary Confirm that permission must be granted to access keystores.
--- a/jdk/test/sun/security/mscapi/IsSunMSCAPIAvailable.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/IsSunMSCAPIAvailable.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,16 +33,6 @@
public static void main(String[] args) throws Exception {
- // Check if the provider is available
- try {
- Class.forName("sun.security.mscapi.SunMSCAPI");
-
- } catch (Exception e) {
- System.out.println(
- "The SunMSCAPI provider is not available on this platform");
- return;
- }
-
// Dynamically register the SunMSCAPI provider
Security.addProvider(new sun.security.mscapi.SunMSCAPI());
@@ -58,7 +48,6 @@
/*
* Secure Random
*/
-
SecureRandom random = SecureRandom.getInstance("Windows-PRNG", p);
System.out.println(" Windows-PRNG is implemented by: " +
random.getClass().getName());
--- a/jdk/test/sun/security/mscapi/IsSunMSCAPIAvailable.sh Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/IsSunMSCAPIAvailable.sh Wed Jul 05 21:02:29 2017 +0200
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
# @test
# @bug 6318171 6931562
+# @requires os.family == "windows"
# @run shell IsSunMSCAPIAvailable.sh
# @summary Basic test of the Microsoft CryptoAPI provider.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/mscapi/IterateWindowsRootStore.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.Provider;
+import java.security.Security;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactorySpi;
+import java.util.Collection;
+import java.util.Enumeration;
+
+/*
+ * @test
+ * @bug 8139436
+ * @summary This test validates an iteration over the Windows-ROOT certificate store
+ * and retrieving all certificates.
+ * Bug 8139436 reports an issue when 3rd party JCE providers would throw exceptions
+ * upon creating Certificate objects.
+ * This would for instance happen when using IAIK 3.15 and Elliptic Curve certificates
+ * are contained in the Windows-ROOT certificate store.
+ * The test uses a simple dummy provider which just throws Exceptions in its CertificateFactory.
+ * To test an external provider, you can use property sun.security.mscapi.testprovider and
+ * set it to the provider class name which has to be constructible by a constructor without
+ * arguments. The provider jar has to be added to the classpath.
+ * E.g. run jtreg with -javaoption:-Dsun.security.mscapi.testprovider=iaik.security.provider.IAIK and
+ * -cpa:<path to iaik_jce.jar>
+ *
+ * @requires os.family == "windows"
+ * @author Christoph Langer
+ * @run main IterateWindowsRootStore
+ */
+public class IterateWindowsRootStore {
+ public static class TestFactory extends CertificateFactorySpi {
+ @Override
+ public Certificate engineGenerateCertificate(InputStream inStream) throws CertificateException {
+ throw new CertificateException("unimplemented");
+ }
+
+ @Override
+ public Collection<? extends Certificate> engineGenerateCertificates(InputStream inStream) throws CertificateException {
+ throw new CertificateException("unimplemented");
+ }
+
+ @Override
+ public CRL engineGenerateCRL(InputStream inStream) throws CRLException {
+ throw new CRLException("unimplemented");
+ }
+
+ @Override
+ public Collection<? extends CRL> engineGenerateCRLs(InputStream inStream) throws CRLException {
+ throw new CRLException("unimplemented");
+ }
+ }
+
+ public static class TestProvider extends Provider {
+ private static final long serialVersionUID = 1L;
+
+ public TestProvider() {
+ super("TestProvider", 0.1, "Test provider for IterateWindowsRootStore");
+
+ /*
+ * Certificates
+ */
+ this.put("CertificateFactory.X.509", "IterateWindowsRootStore$TestFactory");
+ this.put("Alg.Alias.CertificateFactory.X509", "X.509");
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ // Try to register a JCE provider from property sun.security.mscapi.testprovider in the first slot
+ // otherwise register a dummy provider which would provoke the issue of bug 8139436
+ boolean providerPrepended = false;
+ String testprovider = System.getProperty("sun.security.mscapi.testprovider");
+ if (testprovider != null && !testprovider.isEmpty()) {
+ try {
+ System.out.println("Trying to prepend external JCE provider " + testprovider);
+ Class<?> providerclass = Class.forName(testprovider);
+ Object provider = providerclass.newInstance();
+ Security.insertProviderAt((Provider)provider, 1);
+ } catch (Exception e) {
+ System.out.println("Could not load JCE provider " + testprovider +". Exception is:");
+ e.printStackTrace(System.out);
+ }
+ providerPrepended = true;
+ System.out.println("Sucessfully prepended JCE provider " + testprovider);
+ }
+ if (!providerPrepended) {
+ System.out.println("Trying to prepend dummy JCE provider");
+ Security.insertProviderAt(new TestProvider(), 1);
+ System.out.println("Sucessfully prepended dummy JCE provider");
+ }
+
+ // load Windows-ROOT KeyStore
+ KeyStore keyStore = KeyStore.getInstance("Windows-ROOT", "SunMSCAPI");
+ keyStore.load(null, null);
+
+ // iterate KeyStore
+ Enumeration<String> aliases = keyStore.aliases();
+ while (aliases.hasMoreElements()) {
+ String alias = aliases.nextElement();
+ System.out.print("Reading certificate for alias: " + alias + "...");
+ keyStore.getCertificate(alias);
+ System.out.println(" done.");
+ }
+ }
+}
--- a/jdk/test/sun/security/mscapi/KeyStoreCompatibilityMode.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/KeyStoreCompatibilityMode.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,17 +38,6 @@
public static void main(String[] args) throws Exception {
- // Check if the provider is available
- try {
- Class.forName("sun.security.mscapi.SunMSCAPI");
-
- } catch (Exception e) {
- System.out.println(
- "The SunMSCAPI provider is not available on this platform: " +
- e);
- return;
- }
-
if (args.length > 0 && "-disable".equals(args[0])) {
mode = false;
} else {
--- a/jdk/test/sun/security/mscapi/KeyStoreCompatibilityMode.sh Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/KeyStoreCompatibilityMode.sh Wed Jul 05 21:02:29 2017 +0200
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -23,9 +23,9 @@
# questions.
#
-
# @test
# @bug 6324294 6931562
+# @requires os.family == "windows"
# @run shell KeyStoreCompatibilityMode.sh
# @summary Confirm that a null stream or password is not permitted when
# compatibility mode is enabled (and vice versa).
--- a/jdk/test/sun/security/mscapi/KeytoolChangeAlias.sh Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/KeytoolChangeAlias.sh Wed Jul 05 21:02:29 2017 +0200
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
# @test
# @bug 6415696 6931562
+# @requires os.family == "windows"
# @run shell KeytoolChangeAlias.sh
# @summary Test "keytool -changealias" using the Microsoft CryptoAPI provider.
--- a/jdk/test/sun/security/mscapi/PrngSlow.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/PrngSlow.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2015 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
/**
* @test
* @bug 6449335
+ * @requires os.family == "windows"
* @summary MSCAPI's PRNG is too slow
* @key randomness
*/
@@ -34,23 +35,15 @@
public static void main(String[] args) throws Exception {
double t = 0.0;
- try {
- SecureRandom sr = null;
- sr = SecureRandom.getInstance("PRNG", "SunMSCAPI");
- long start = System.nanoTime();
- int x = 0;
- for(int i = 0; i < 10000; i++) {
- if (i % 100 == 0) System.err.print(".");
- if (sr.nextBoolean()) x++;
- };
- t = (System.nanoTime() - start) / 1000000000.0;
- System.err.println("\nSpend " + t + " seconds");
- } catch (Exception e) {
- // Not supported here, maybe not a Win32
- System.err.println("Cannot find PRNG for SunMSCAPI or other mysterious bugs");
- e.printStackTrace();
- return;
- }
+ SecureRandom sr = null;
+ sr = SecureRandom.getInstance("Windows-PRNG", "SunMSCAPI");
+ long start = System.nanoTime();
+ for (int i = 0; i < 10000; i++) {
+ if (i % 100 == 0) System.err.print(".");
+ sr.nextBoolean();
+ };
+ t = (System.nanoTime() - start) / 1000000000.0;
+ System.err.println("\nSpend " + t + " seconds");
if (t > 5)
throw new RuntimeException("Still too slow");
}
--- a/jdk/test/sun/security/mscapi/PublicKeyInterop.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/PublicKeyInterop.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,8 +38,6 @@
public class PublicKeyInterop {
public static void main(String[] arg) throws Exception {
- PrivateKey privKey = null;
- Certificate cert = null;
KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, null);
System.out.println("Loaded keystore: Windows-MY");
--- a/jdk/test/sun/security/mscapi/PublicKeyInterop.sh Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/PublicKeyInterop.sh Wed Jul 05 21:02:29 2017 +0200
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2015 Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
# @test
# @bug 6888925
+# @requires os.family == "windows"
# @run shell PublicKeyInterop.sh
# @summary SunMSCAPI's Cipher can't use RSA public keys obtained from other
# sources.
--- a/jdk/test/sun/security/mscapi/RSAEncryptDecrypt.sh Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/RSAEncryptDecrypt.sh Wed Jul 05 21:02:29 2017 +0200
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
# @test
# @bug 6457422 6931562
+# @requires os.family == "windows"
# @run shell RSAEncryptDecrypt.sh
# @summary Confirm that plaintext can be encrypted and then decrypted using the
# RSA cipher in the SunMSCAPI crypto provider. NOTE: The RSA cipher is
--- a/jdk/test/sun/security/mscapi/ShortRSAKey1024.sh Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/ShortRSAKey1024.sh Wed Jul 05 21:02:29 2017 +0200
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
# @test
# @bug 7106773
# @summary 512 bits RSA key cannot work with SHA384 and SHA512
+# @requires os.family == "windows"
# @run shell ShortRSAKey1024.sh 1024
# @run shell ShortRSAKey1024.sh 768
# @run shell ShortRSAKey1024.sh 512
--- a/jdk/test/sun/security/mscapi/ShortRSAKeyWithinTLS.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/ShortRSAKeyWithinTLS.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,12 +22,9 @@
*/
import java.io.*;
-import java.net.*;
-import java.util.*;
import java.security.*;
import javax.net.*;
import javax.net.ssl.*;
-import java.lang.reflect.*;
import sun.security.util.KeyUtil;
--- a/jdk/test/sun/security/mscapi/SignUsingNONEwithRSA.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/SignUsingNONEwithRSA.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -118,12 +118,12 @@
ks.load(null, null);
System.out.println("Loaded keystore: Windows-MY");
- Enumeration e = ks.aliases();
+ Enumeration<String> e = ks.aliases();
PrivateKey privateKey = null;
PublicKey publicKey = null;
while (e.hasMoreElements()) {
- String alias = (String) e.nextElement();
+ String alias = e.nextElement();
if (alias.equals("6578658")) {
System.out.println("Loaded entry: " + alias);
privateKey = (PrivateKey) ks.getKey(alias, null);
--- a/jdk/test/sun/security/mscapi/SignUsingNONEwithRSA.sh Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/SignUsingNONEwithRSA.sh Wed Jul 05 21:02:29 2017 +0200
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
# @test
# @bug 6578658
+# @requires os.family == "windows"
# @run shell SignUsingNONEwithRSA.sh
# @summary Sign using the NONEwithRSA signature algorithm from SunMSCAPI
# @key intermittent
--- a/jdk/test/sun/security/mscapi/SignUsingSHA2withRSA.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/SignUsingSHA2withRSA.java Wed Jul 05 21:02:29 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -58,12 +58,12 @@
ks.load(null, null);
System.out.println("Loaded keystore: Windows-MY");
- Enumeration e = ks.aliases();
+ Enumeration<String> e = ks.aliases();
PrivateKey privateKey = null;
PublicKey publicKey = null;
while (e.hasMoreElements()) {
- String alias = (String) e.nextElement();
+ String alias = e.nextElement();
if (alias.equals("6753664")) {
System.out.println("Loaded entry: " + alias);
privateKey = (PrivateKey) ks.getKey(alias, null);
--- a/jdk/test/sun/security/mscapi/SignUsingSHA2withRSA.sh Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/SignUsingSHA2withRSA.sh Wed Jul 05 21:02:29 2017 +0200
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
# @test
# @bug 6753664
+# @requires os.family == "windows"
# @run shell SignUsingSHA2withRSA.sh
# @summary Support SHA256 (and higher) in SunMSCAPI
# @key intermittent
--- a/jdk/test/sun/security/mscapi/SignatureOffsets.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/SignatureOffsets.java Wed Jul 05 21:02:29 2017 +0200
@@ -36,6 +36,7 @@
* and passing in different signature offset (0, 33, 66, 99).
* @library /lib/testlibrary
* @compile ../../../java/security/Signature/Offsets.java
+ * @requires os.family == "windows"
* @run main SignatureOffsets SunMSCAPI NONEwithRSA
* @run main SignatureOffsets SunMSCAPI MD2withRSA
* @run main SignatureOffsets SunMSCAPI MD5withRSA
--- a/jdk/test/sun/security/mscapi/SignedObjectChain.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/SignedObjectChain.java Wed Jul 05 21:02:29 2017 +0200
@@ -25,6 +25,7 @@
* @test
* @bug 8050374
* @compile ../../../java/security/SignedObject/Chain.java
+ * @requires os.family == "windows"
* @summary Verify a chain of signed objects
*/
public class SignedObjectChain {
--- a/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java Wed Jul 05 21:02:29 2017 +0200
@@ -28,8 +28,6 @@
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateCrtKey;
-import java.util.HashSet;
-import java.util.Set;
/*
* @test
@@ -37,6 +35,7 @@
* @modules java.base/sun.security.x509
* java.base/sun.security.tools.keytool
* @summary sun/security/mscapi/ShortRSAKey1024.sh fails intermittently
+ * @requires os.family == "windows"
*/
public class SmallPrimeExponentP {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/pkcs/pkcs10/PKCS10AttrEncoding.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8048357
+ * @summary test DER encoding of PKCS10 attributes
+ * @modules java.base/sun.security.pkcs
+ * java.base/sun.security.pkcs10
+ * java.base/sun.security.util
+ * java.base/sun.security.x509
+ * @compile -XDignore.symbol.file PKCS10AttrEncoding.java
+ * @run main PKCS10AttrEncoding
+ */
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.util.Enumeration;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import sun.security.pkcs.PKCS9Attribute;
+import sun.security.pkcs10.PKCS10;
+import sun.security.pkcs10.PKCS10Attribute;
+import sun.security.pkcs10.PKCS10Attributes;
+import sun.security.util.ObjectIdentifier;
+import sun.security.x509.X500Name;
+import sun.security.x509.X509Key;
+
+public class PKCS10AttrEncoding {
+
+ static final ObjectIdentifier[] ids = {
+ PKCS9Attribute.CONTENT_TYPE_OID, // ContentType
+ PKCS9Attribute.SIGNING_TIME_OID, // SigningTime
+ PKCS9Attribute.CHALLENGE_PASSWORD_OID // ChallengePassword
+ };
+ static int failedCount = 0;
+ static HashMap<ObjectIdentifier, Object> constructedMap = new HashMap<>();
+
+ public static void main(String[] args) throws Exception {
+
+ // initializations
+ int len = ids.length;
+ Object[] values = {
+ new ObjectIdentifier("1.2.3.4"),
+ new GregorianCalendar(1970, 1, 25, 8, 56, 7).getTime(),
+ "challenging"
+ };
+ for (int j = 0; j < len; j++) {
+ constructedMap.put(ids[j], values[j]);
+ }
+
+ X500Name subject = new X500Name("cn=Test");
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
+ String sigAlg = "DSA";
+
+ keyGen.initialize(512);
+
+ KeyPair pair = keyGen.generateKeyPair();
+ X509Key publicKey = (X509Key) pair.getPublic();
+ PrivateKey privateKey = pair.getPrivate();
+
+ Signature signature = Signature.getInstance(sigAlg);
+ signature.initSign(privateKey);
+
+ // Create the PKCS10 request
+ PKCS10Attribute[] attrs = new PKCS10Attribute[len];
+ for (int j = 0; j < len; j++) {
+ attrs[j] = new PKCS10Attribute(ids[j], values[j]);
+ }
+ PKCS10 req = new PKCS10(publicKey, new PKCS10Attributes(attrs));
+ System.out.println("List of attributes in constructed PKCS10 "
+ + "request: ");
+ checkAttributes(req.getAttributes().getElements());
+
+ // Encode the PKCS10 request and generate another PKCS10 request from
+ // the encoded byte array
+ req.encodeAndSign(subject, signature);
+ PKCS10 resp = new PKCS10(req.getEncoded());
+ System.out.println("List of attributes in DER encoded PKCS10 Request:");
+ checkAttributes(resp.getAttributes().getElements());
+
+ if (failedCount > 0) {
+ throw new RuntimeException("Attributes Compared : Failed");
+ }
+ System.out.println("Attributes Compared : Pass");
+ }
+
+ static void checkAttributes(Enumeration attrs) {
+ int numOfAttrs = 0;
+ while (attrs.hasMoreElements()) {
+ numOfAttrs ++;
+ PKCS10Attribute attr = (PKCS10Attribute) attrs.nextElement();
+
+ if (constructedMap.containsKey(attr.getAttributeId())) {
+ if (constructedMap.get(attr.getAttributeId()).
+ equals(attr.getAttributeValue())) {
+ System.out.print("AttributeId: " + attr.getAttributeId());
+ System.out.println(" AttributeValue: "
+ + attr.getAttributeValue());
+ } else {
+ failedCount++;
+ System.out.print("< AttributeId: " + attr.getAttributeId());
+ System.out.println(" AttributeValue: " + constructedMap.
+ get(attr.getAttributeId()));
+ System.out.print("< AttributeId: " + attr.getAttributeId());
+ System.out.println(" AttributeValue: "
+ + attr.getAttributeValue());
+ }
+ } else {
+ failedCount++;
+ System.out.println("No " + attr.getAttributeId()
+ + " in DER encoded PKCS10 Request");
+ }
+ }
+ if(numOfAttrs != constructedMap.size()){
+ failedCount++;
+ System.out.println("Incorrect number of attributes.");
+
+ }
+ System.out.println();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/pkcs/pkcs10/PKCS10AttributeReader.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8048357
+ * @summary Read in a file containing a DER encoded PKCS10 certificate request,
+ * flanked with "begin" and "end" lines.
+ * @modules java.base/sun.security.pkcs
+ * java.base/sun.security.pkcs10
+ * java.base/sun.security.util
+ * @compile -XDignore.symbol.file PKCS10AttributeReader.java
+ * @run main PKCS10AttributeReader
+ */
+import java.util.Base64;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Date;
+import sun.security.pkcs.PKCS9Attribute;
+import sun.security.pkcs10.PKCS10Attribute;
+import sun.security.pkcs10.PKCS10Attributes;
+import sun.security.util.DerInputStream;
+import sun.security.util.ObjectIdentifier;
+
+/*
+ Tests only reads DER encoding files, contents of corresponding asn.1 files
+ are copied below for reference.
+
+ # An attribute set for testing with PKCS10.
+
+ {A0 # implicit tag
+ {SEQ # Content Type
+ {OID 1.2.840.113549.1.9.3}
+ {SET
+ {OID "1234"}
+ }
+ }
+ {SEQ # Challenge Password
+ {OID 1.2.840.113549.1.9.7}
+ {SET
+ {T61String "GuessWhoAmI"}
+ }
+ }
+ {SEQ # Signing Time
+ {OID 1.2.840.113549.1.9.5}
+ {SET
+ {UTCTime "970422145010Z"}
+ }
+ }
+ }
+ */
+public class PKCS10AttributeReader {
+ // DER encoded files are binary files, to avoid attaching binary files,
+ // DER files were encoded in base64
+ static final String ATTRIBS = "oE8wEwYJKoZIhvcNAQkDMQYGBDEyMzQwGgYJKoZIhv"
+ + "cNAQkHMQ0UC0d1ZXNzV2hv\nQW1JMBwGCSqGSIb3DQEJBTEPFw05NzA0MjIxND"
+ + "UwMTBa";
+
+ public static void main(String[] args) throws Exception {
+
+ // Decode base64 encoded DER file
+ byte[] pkcs10Bytes = Base64.getMimeDecoder().decode(ATTRIBS.getBytes());
+
+ HashMap<ObjectIdentifier, Object> RequestStander = new HashMap() {
+ {
+ put(PKCS9Attribute.CHALLENGE_PASSWORD_OID, "GuessWhoAmI");
+ put(PKCS9Attribute.SIGNING_TIME_OID, new Date(861720610000L));
+ put(PKCS9Attribute.CONTENT_TYPE_OID,
+ new ObjectIdentifier("1.9.50.51.52"));
+ }
+ };
+
+ int invalidNum = 0;
+ PKCS10Attributes resp = new PKCS10Attributes(
+ new DerInputStream(pkcs10Bytes));
+ Enumeration eReq = resp.getElements();
+ int numOfAttrs = 0;
+ while (eReq.hasMoreElements()) {
+ numOfAttrs++;
+ PKCS10Attribute attr = (PKCS10Attribute) eReq.nextElement();
+ if (RequestStander.containsKey(attr.getAttributeId())) {
+ if (RequestStander.get(attr.getAttributeId())
+ .equals(attr.getAttributeValue())) {
+ System.out.println(attr.getAttributeId() + " "
+ + attr.getAttributeValue());
+ } else {
+ invalidNum++;
+ System.out.println("< " + attr.getAttributeId() + " "
+ + attr.getAttributeValue());
+ System.out.println("< " + attr.getAttributeId() + " "
+ + RequestStander.get(attr.getAttributeId()));
+ }
+ } else {
+ invalidNum++;
+ System.out.println("No" + attr.getAttributeId()
+ + "in Certificate Request list");
+ }
+ }
+ if (numOfAttrs != RequestStander.size()) {
+ invalidNum++;
+ System.out.println("Incorrect number of attributes.");
+ }
+ System.out.println();
+ if (invalidNum > 0) {
+ throw new RuntimeException(
+ "Attributes Compared with Stander :" + " Failed");
+ }
+ System.out.println("Attributes Compared with Stander: Pass");
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/pkcs/pkcs7/PKCS7VerifyTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8048357
+ * @summary Read signed data in one or more PKCS7 objects from individual files,
+ * verify SignerInfos and certificate chain.
+ * @modules java.base/sun.security.pkcs
+ * @run main PKCS7VerifyTest PKCS7TEST.DSA.base64
+ * @run main PKCS7VerifyTest PKCS7TEST.DSA.base64 PKCS7TEST.SF
+ */
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.cert.X509Certificate;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+import sun.security.pkcs.PKCS7;
+import sun.security.pkcs.SignerInfo;
+
+public class PKCS7VerifyTest {
+
+ static final String TESTSRC = System.getProperty("test.src", ".");
+ static final String FS = File.separator;
+ static final String FILEPATH = TESTSRC + FS + "jarsigner" + FS + "META-INF"
+ + FS;
+
+ public static void main(String[] args) throws Exception {
+ if (args.length == 0) {
+ throw new RuntimeException("usage: java JarVerify <file1> <file2>");
+ }
+
+ // The command " java PKCS7VerifyTest file1 [file2] "
+ // treats file1 as containing the DER encoding of a PKCS7 signed data
+ // object. If file2 is absent, the program verifies that some signature
+ // (SignerInfo) file1 correctly signs the data contained in the
+ // ContentInfo component of the PKCS7 object encoded by file1. If file2
+ // is present, the program verifies file1 contains a correct signature
+ // for the contents of file2.
+
+ PKCS7 pkcs7;
+ byte[] data;
+
+ // to avoid attaching binary DSA file, the DSA file was encoded
+ // in Base64, decode encoded Base64 DSA file below
+ byte[] base64Bytes = Files.readAllBytes(Paths.get(FILEPATH + args[0]));
+ pkcs7 = new PKCS7(new ByteArrayInputStream(
+ Base64.getMimeDecoder().decode(base64Bytes)));
+ if (args.length < 2) {
+ data = null;
+ } else {
+ data = Files.readAllBytes(Paths.get(FILEPATH + args[1]));
+
+ }
+
+ SignerInfo[] signerInfos = pkcs7.verify(data);
+
+ if (signerInfos == null) {
+ throw new RuntimeException("no signers verify");
+ }
+ System.out.println("Verifying SignerInfos:");
+ for (SignerInfo signerInfo : signerInfos) {
+ System.out.println(signerInfo.toString());
+ }
+
+ X509Certificate certs[] = pkcs7.getCertificates();
+
+ HashMap<String, X509Certificate> certTable = new HashMap(certs.length);
+ for (X509Certificate cert : certs) {
+ certTable.put(cert.getSubjectDN().toString(), cert);
+ }
+
+ // try to verify all the certs
+ for (Map.Entry<String, X509Certificate> entry : certTable.entrySet()) {
+
+ X509Certificate cert = entry.getValue();
+ X509Certificate issuerCert = certTable
+ .get(cert.getIssuerDN().toString());
+
+ System.out.println("Subject: " + cert.getSubjectDN());
+ if (issuerCert == null) {
+ System.out.println("Issuer certificate not found");
+ } else {
+ System.out.println("Issuer: " + cert.getIssuerDN());
+ cert.verify(issuerCert.getPublicKey());
+ System.out.println("Cert verifies.");
+ }
+ System.out.println();
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/pkcs/pkcs7/SignerOrder.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8048357
+ * @summary test PKCS7 data signing, encoding and verification
+ * @modules java.base/sun.security.pkcs
+ * java.base/sun.security.util
+ * java.base/sun.security.x509
+ * @run main SignerOrder
+ */
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import sun.misc.HexDumpEncoder;
+import sun.security.pkcs.ContentInfo;
+import sun.security.pkcs.PKCS7;
+import sun.security.pkcs.SignerInfo;
+import sun.security.util.DerOutputStream;
+import sun.security.x509.AlgorithmId;
+import sun.security.x509.CertificateAlgorithmId;
+import sun.security.x509.CertificateSerialNumber;
+import sun.security.x509.CertificateValidity;
+import sun.security.x509.CertificateVersion;
+import sun.security.x509.CertificateX509Key;
+import sun.security.x509.X500Name;
+import sun.security.x509.X509CertImpl;
+import sun.security.x509.X509CertInfo;
+import sun.security.x509.X509Key;
+
+public class SignerOrder {
+
+ static final HexDumpEncoder hexDump = new HexDumpEncoder();
+
+ //signer infos
+ static final byte[] data1 = "12345".getBytes();
+ static final byte[] data2 = "abcde".getBytes();
+
+ public static void main(String[] argv) throws Exception {
+
+ SignerInfo[] signerInfos = new SignerInfo[9];
+ SimpleSigner signer1 = new SimpleSigner(null, null, null, null);
+ signerInfos[8] = signer1.genSignerInfo(data1);
+ signerInfos[7] = signer1.genSignerInfo(new byte[]{});
+ signerInfos[6] = signer1.genSignerInfo(data2);
+
+ SimpleSigner signer2 = new SimpleSigner(null, null, null, null);
+ signerInfos[5] = signer2.genSignerInfo(data1);
+ signerInfos[4] = signer2.genSignerInfo(new byte[]{});
+ signerInfos[3] = signer2.genSignerInfo(data2);
+
+ SimpleSigner signer3 = new SimpleSigner(null, null, null, null);
+ signerInfos[2] = signer3.genSignerInfo(data1);
+ signerInfos[1] = signer3.genSignerInfo(new byte[]{});
+ signerInfos[0] = signer3.genSignerInfo(data2);
+
+ ContentInfo contentInfo = new ContentInfo(data1);
+
+ AlgorithmId[] algIds = {new AlgorithmId(AlgorithmId.SHA256_oid)};
+
+ X509Certificate[] certs = {signer3.getCert(), signer2.getCert(),
+ signer1.getCert()};
+
+ PKCS7 pkcs71 = new PKCS7(algIds, contentInfo,
+ certs,
+ signerInfos);
+
+ System.out.println("SignerInfos in original.");
+ printSignerInfos(pkcs71.getSignerInfos());
+
+ DerOutputStream out = new DerOutputStream();
+ pkcs71.encodeSignedData(out);
+
+ PKCS7 pkcs72 = new PKCS7(out.toByteArray());
+ System.out.println("\nSignerInfos read back in:");
+ printSignerInfos(pkcs72.getSignerInfos());
+
+ System.out.println("Verified signers of original:");
+ SignerInfo[] verifs1 = pkcs71.verify();
+
+ System.out.println("Verified signers of after read-in:");
+ SignerInfo[] verifs2 = pkcs72.verify();
+
+ if (verifs1.length != verifs2.length) {
+ throw new RuntimeException("Length or Original vs read-in "
+ + "should be same");
+ }
+ }
+
+ static void printSignerInfos(SignerInfo signerInfo) throws IOException {
+ ByteArrayOutputStream strm = new ByteArrayOutputStream();
+ signerInfo.derEncode(strm);
+ System.out.println("SignerInfo, length: "
+ + strm.toByteArray().length);
+ System.out.println(hexDump.encode(strm.toByteArray()));
+ System.out.println("\n");
+ strm.reset();
+ }
+
+ static void printSignerInfos(SignerInfo[] signerInfos) throws IOException {
+ ByteArrayOutputStream strm = new ByteArrayOutputStream();
+ for (int i = 0; i < signerInfos.length; i++) {
+ signerInfos[i].derEncode(strm);
+ System.out.println("SignerInfo[" + i + "], length: "
+ + strm.toByteArray().length);
+ System.out.println(hexDump.encode(strm.toByteArray()));
+ System.out.println("\n");
+ strm.reset();
+ }
+ }
+
+}
+
+/**
+ * A simple extension of sun.security.x509.X500Signer that adds a no-fuss
+ * signing algorithm.
+ */
+class SimpleSigner {
+
+ private final Signature sig;
+ private final X500Name agent;
+ private final AlgorithmId digestAlgId;
+ private final AlgorithmId encryptionAlgId;
+ private final AlgorithmId algId; // signature algid;
+ //combines digest + encryption
+ private final X509Key publicKey;
+ private final PrivateKey privateKey;
+ private final X509Certificate cert;
+
+ public SimpleSigner(String digestAlg,
+ String encryptionAlg,
+ KeyPair keyPair,
+ X500Name agent) throws Exception {
+
+ if (agent == null) {
+ agent = new X500Name("cn=test");
+ }
+ if (digestAlg == null) {
+ digestAlg = "SHA";
+ }
+ if (encryptionAlg == null) {
+ encryptionAlg = "DSA";
+ }
+ if (keyPair == null) {
+ KeyPairGenerator keyGen =
+ KeyPairGenerator.getInstance(encryptionAlg);
+ keyGen.initialize(1024);
+ keyPair = keyGen.generateKeyPair();
+ }
+ publicKey = (X509Key) keyPair.getPublic();
+ privateKey = keyPair.getPrivate();
+
+ if ("DSA".equals(encryptionAlg)) {
+ this.sig = Signature.getInstance(encryptionAlg);
+ } else { // RSA
+ this.sig = Signature.getInstance(digestAlg + "/" + encryptionAlg);
+ }
+ this.sig.initSign(privateKey);
+
+ this.agent = agent;
+ this.digestAlgId = AlgorithmId.get(digestAlg);
+ this.encryptionAlgId = AlgorithmId.get(encryptionAlg);
+ this.algId = AlgorithmId.get(this.sig.getAlgorithm());
+
+ this.cert = getSelfCert();
+ }
+
+ /**
+ * Take the data and sign it.
+ *
+ * @param buf buffer holding the next chunk of the data to be signed
+ * @param offset starting point of to-be-signed data
+ * @param len how many bytes of data are to be signed
+ * @return the signature for the input data.
+ * @exception SignatureException on errors.
+ */
+ public byte[] simpleSign(byte[] buf, int offset, int len)
+ throws SignatureException {
+ sig.update(buf, offset, len);
+ return sig.sign();
+ }
+
+ /**
+ * Returns the digest algorithm used to sign.
+ */
+ public AlgorithmId getDigestAlgId() {
+ return digestAlgId;
+ }
+
+ /**
+ * Returns the encryption algorithm used to sign.
+ */
+ public AlgorithmId getEncryptionAlgId() {
+ return encryptionAlgId;
+ }
+
+ /**
+ * Returns the name of the signing agent.
+ */
+ public X500Name getSigner() {
+ return agent;
+ }
+
+ public X509Certificate getCert() {
+ return cert;
+ }
+
+ private X509Certificate getSelfCert() throws Exception {
+ long validity = 1000;
+ X509CertImpl certLocal;
+ Date firstDate, lastDate;
+
+ firstDate = new Date();
+ lastDate = new Date();
+ lastDate.setTime(lastDate.getTime() + validity + 1000);
+
+ CertificateValidity interval = new CertificateValidity(firstDate,
+ lastDate);
+
+ X509CertInfo info = new X509CertInfo();
+ // Add all mandatory attributes
+ info.set(X509CertInfo.VERSION,
+ new CertificateVersion(CertificateVersion.V1));
+ info.set(X509CertInfo.SERIAL_NUMBER,
+ new CertificateSerialNumber(
+ (int) (firstDate.getTime() / 1000)));
+ info.set(X509CertInfo.ALGORITHM_ID,
+ new CertificateAlgorithmId(algId));
+ info.set(X509CertInfo.SUBJECT, agent);
+ info.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));
+ info.set(X509CertInfo.VALIDITY, interval);
+ info.set(X509CertInfo.ISSUER, agent);
+
+ certLocal = new X509CertImpl(info);
+ certLocal.sign(privateKey, algId.getName());
+
+ return certLocal;
+ }
+
+ public SignerInfo genSignerInfo(byte[] data) throws SignatureException {
+ return new SignerInfo((X500Name) cert.getIssuerDN(),
+ new BigInteger("" + cert.getSerialNumber()),
+ getDigestAlgId(), algId,
+ simpleSign(data, 0, data.length));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/pkcs/pkcs7/jarsigner/META-INF/MANIFEST.MF Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,82 @@
+Manifest-Version: 1.0
+
+Name: CheckCerts.class
+Digest-Algorithms: SHA
+SHA-Digest: xLygljhRro6990piIVEilVI8szQ=
+
+Name: ContentInfoTest.class
+Digest-Algorithms: SHA
+SHA-Digest: TSVdEMQW2gdFi6qeba+UixdHSdo=
+
+Name: JarVerify.class
+Digest-Algorithms: SHA
+SHA-Digest: Wg+PiDzunNGH4KrWAp00/okp39s=
+
+Name: JarVerify2.class
+Digest-Algorithms: SHA
+SHA-Digest: 5uYBQxwGWgYmNBwhnWRbymeXmWM=
+
+Name: PKCS7Read.class
+Digest-Algorithms: SHA
+SHA-Digest: JPIxttHBfRpQaFyiQJ2Wfkvj/ls=
+
+Name: PKCS7Test.class
+Digest-Algorithms: SHA
+SHA-Digest: R64SXXgZrOvGiO/eMsfG/T1Vn30=
+
+Name: PKCS7Test10.class
+Digest-Algorithms: SHA
+SHA-Digest: 2R0yxuxRHTPqdAzJJcrvqkpbQgo=
+
+Name: PKCS7Test11.class
+Digest-Algorithms: SHA
+SHA-Digest: /0HcwnpQi0hwJsJtvt5peWFGvtc=
+
+Name: PKCS7Test12.class
+Digest-Algorithms: SHA
+SHA-Digest: s5CcqimfRqR9CW25tFBY0JK3RVU=
+
+Name: PKCS7Test2.class
+Digest-Algorithms: SHA
+SHA-Digest: 71VkFEMUle5sjXNFbSW31F1ZJ58=
+
+Name: PKCS7Test3.class
+Digest-Algorithms: SHA
+SHA-Digest: mU/D5C6SgPRmwoLQzwF5VnN3aqM=
+
+Name: PKCS7Test4.class
+Digest-Algorithms: SHA
+SHA-Digest: ss9NFvxF8emaEjdKdvtzWXfs0/E=
+
+Name: PKCS7Test5.class
+Digest-Algorithms: SHA
+SHA-Digest: DHvQ20UAXoYgfCPAOeCOrglsJwU=
+
+Name: PKCS7Test6.class
+Digest-Algorithms: SHA
+SHA-Digest: aiCb8chroH7XDaNfAz6wr57lXsA=
+
+Name: PKCS7Test7.class
+Digest-Algorithms: SHA
+SHA-Digest: UoieXLC68alFgfD/Q1NW9/r2kaY=
+
+Name: PKCS7Test8.class
+Digest-Algorithms: SHA
+SHA-Digest: eMW7mq5b/KVB1M5L76wcV1+uFQs=
+
+Name: PKCS7Test9.class
+Digest-Algorithms: SHA
+SHA-Digest: EEWCZG1creWjqVZVIEgr0on3y6A=
+
+Name: SignerInfoTest.class
+Digest-Algorithms: SHA
+SHA-Digest: l6SNfpnFipGg8gy4XqY3HhA0RrY=
+
+Name: SignerInfoTest2.class
+Digest-Algorithms: SHA
+SHA-Digest: 5jbzlkZqXKNmmmE+pcjQka8D6WE=
+
+Name: SimpleSigner.class
+Digest-Algorithms: SHA
+SHA-Digest: l9ODQHY4wxhIvLw4/B0qe9NjwxQ=
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/pkcs/pkcs7/jarsigner/META-INF/PKCS7TEST.DSA.base64 Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,60 @@
+MIILKAYJKoZIhvcNAQcCoIILGTCCCxUCAQExCzAJBgUrDgMCGgUAMIIHbQYJKoZI
+hvcNAQcBoIIHXgSCB1pTaWduYXR1cmUtVmVyc2lvbjogMS4wDQoNCk5hbWU6IENo
+ZWNrQ2VydHMuY2xhc3MNCkRpZ2VzdC1BbGdvcml0aG1zOiBTSEENClNIQS1EaWdl
+c3Q6IHlhMXh3dnNRTytEUnBRYnczRmgyblJCMkpRYz0NCg0KTmFtZTogQ29udGVu
+dEluZm9UZXN0LmNsYXNzDQpEaWdlc3QtQWxnb3JpdGhtczogU0hBDQpTSEEtRGln
+ZXN0OiBDYStFSmFrVTZ6dzRLQWhvcWNuQ3BOcWsyTEk9DQoNCk5hbWU6IEphclZl
+cmlmeS5jbGFzcw0KRGlnZXN0LUFsZ29yaXRobXM6IFNIQQ0KU0hBLURpZ2VzdDog
+K0RHYVdXa25md2U0Wk9wc29NVEZ6ZldSdmhRPQ0KDQpOYW1lOiBKYXJWZXJpZnky
+LmNsYXNzDQpEaWdlc3QtQWxnb3JpdGhtczogU0hBDQpTSEEtRGlnZXN0OiBHcUR6
+WXlZNFAvV0g1SEt2aVdxWHR0UGc1ckU9DQoNCk5hbWU6IFBLQ1M3UmVhZC5jbGFz
+cw0KRGlnZXN0LUFsZ29yaXRobXM6IFNIQQ0KU0hBLURpZ2VzdDogUW1mOEs5aFhW
+bHdJZFBZNm52MmpGUGZHcWtBPQ0KDQpOYW1lOiBQS0NTN1Rlc3QuY2xhc3MNCkRp
+Z2VzdC1BbGdvcml0aG1zOiBTSEENClNIQS1EaWdlc3Q6IEdiZS9nenl2MkY1OGY2
+RUVoU1oxQnFHWHRsbz0NCg0KTmFtZTogUEtDUzdUZXN0MTAuY2xhc3MNCkRpZ2Vz
+dC1BbGdvcml0aG1zOiBTSEENClNIQS1EaWdlc3Q6IDh3QnFXLy9lVzJzTlJJOTFi
+TFlFT29kY2dhRT0NCg0KTmFtZTogUEtDUzdUZXN0MTEuY2xhc3MNCkRpZ2VzdC1B
+bGdvcml0aG1zOiBTSEENClNIQS1EaWdlc3Q6IGJYaExLRXNsY3VFWGk0dS9haGdU
+MnE2dGNFVT0NCg0KTmFtZTogUEtDUzdUZXN0MTIuY2xhc3MNCkRpZ2VzdC1BbGdv
+cml0aG1zOiBTSEENClNIQS1EaWdlc3Q6IDlLRVkxYjUyUUxtTjBxei81ejB3QkZy
+T216MD0NCg0KTmFtZTogUEtDUzdUZXN0Mi5jbGFzcw0KRGlnZXN0LUFsZ29yaXRo
+bXM6IFNIQQ0KU0hBLURpZ2VzdDogK1VhMzIvMlE4RjJiclFRbVNYWCtYUytNL2g0
+PQ0KDQpOYW1lOiBQS0NTN1Rlc3QzLmNsYXNzDQpEaWdlc3QtQWxnb3JpdGhtczog
+U0hBDQpTSEEtRGlnZXN0OiAwSFhVWnlhU2ZkZUtlZThuWnpFalJTeXJldTQ9DQoN
+Ck5hbWU6IFBLQ1M3VGVzdDQuY2xhc3MNCkRpZ2VzdC1BbGdvcml0aG1zOiBTSEEN
+ClNIQS1EaWdlc3Q6IEo3eXJTMjRvS3VTZ2F1dHZkemhxQmo3ZGJjUT0NCg0KTmFt
+ZTogUEtDUzdUZXN0NS5jbGFzcw0KRGlnZXN0LUFsZ29yaXRobXM6IFNIQQ0KU0hB
+LURpZ2VzdDogSlR2OVdTb3gxTEVTUjJMcTdzMFVxU2x0RFNRPQ0KDQpOYW1lOiBQ
+S0NTN1Rlc3Q2LmNsYXNzDQpEaWdlc3QtQWxnb3JpdGhtczogU0hBDQpTSEEtRGln
+ZXN0OiBnR3Yra05oK3UzSFExdHp4bGNBVzdTcEZUS2s9DQoNCk5hbWU6IFBLQ1M3
+VGVzdDcuY2xhc3MNCkRpZ2VzdC1BbGdvcml0aG1zOiBTSEENClNIQS1EaWdlc3Q6
+IGZpSEYxYUExYWN6czFPd0V5OEc3VkMrcjdMST0NCg0KTmFtZTogUEtDUzdUZXN0
+OC5jbGFzcw0KRGlnZXN0LUFsZ29yaXRobXM6IFNIQQ0KU0hBLURpZ2VzdDogNzRU
+VzdJOVZPdzVWZ0x2aFJtRGZxRVd2ZkFRPQ0KDQpOYW1lOiBQS0NTN1Rlc3Q5LmNs
+YXNzDQpEaWdlc3QtQWxnb3JpdGhtczogU0hBDQpTSEEtRGlnZXN0OiAxY0JJbkdU
+Y08xQVFaKy8wdmhGa2laV3dsQTA9DQoNCk5hbWU6IFNpZ25lckluZm9UZXN0LmNs
+YXNzDQpEaWdlc3QtQWxnb3JpdGhtczogU0hBDQpTSEEtRGlnZXN0OiBjRlk0Q3RT
+anphMUErV2pBS05TVnF1cGpSWUU9DQoNCk5hbWU6IFNpZ25lckluZm9UZXN0Mi5j
+bGFzcw0KRGlnZXN0LUFsZ29yaXRobXM6IFNIQQ0KU0hBLURpZ2VzdDogYU5NMEZQ
+MHpFelF6eGxYeDZxQ0J4dWtta0hRPQ0KDQpOYW1lOiBTaW1wbGVTaWduZXIuY2xh
+c3MNCkRpZ2VzdC1BbGdvcml0aG1zOiBTSEENClNIQS1EaWdlc3Q6IC9MV0NzbkM3
+TVpNUjZHb3czeTJjdnA3STBTTT0NCg0KoIICvzCCArswggJ3AgUA59UzNDALBgcq
+hkjOOAQDBQAwdTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlD
+dXBlcnRpbm8xGTAXBgNVBAoTEFN1biBNaWNyb3N5c3RlbXMxETAPBgNVBAsTCEph
+dmFTb2Z0MRcwFQYDVQQDEw5Eb3VnbGFzIEhvb3ZlcjAeFw05NzEwMDIxODEyMDda
+Fw05NzEyMzExNzEyMDdaMHUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTESMBAG
+A1UEBxMJQ3VwZXJ0aW5vMRkwFwYDVQQKExBTdW4gTWljcm9zeXN0ZW1zMREwDwYD
+VQQLEwhKYXZhU29mdDEXMBUGA1UEAxMORG91Z2xhcyBIb292ZXIwggFRMIHoBgcq
+hkjOOAQBMIHcAmEA6eZCWZ01XzfJf/01ZxILjiXJzUPpJ7OpZw++xdiQFBki0sOz
+rSSACTeZhp0ehGqrSfqwrSbSzmoiIZ1HC859d31KIfvpwnC1f2BwAvPO+Dk2lM9F
+7jaIwRqMVqsSej2vAhUAnNvYTJ8awvOND4D0KrlS5zOL9RECYDBHCtWgBfsUzi2d
+zYfji8fRscX6y67L6V8ZCqejHSPE27y+BhdFREAaWywCCWXYwr0hcdNmhEV3H3S6
+CE0gKdg8HBWFR/Op8aJxW+I9Ua5NPlofanBk8xaTOjRtP1KSUgNkAAJhAMN5uB+B
+ZJ0W2UjXMyKoFUFXRYiLpnaSw63kl9tKnR9R5rEreiyHQ5IelPxjwCHGgTbYK0y+
+xKTGHVWiQN/YJmHLbSrcSSM/d89aR/sVbGoAwQOyYraFGUNIOTQjjXcXCjALBgcq
+hkjOOAQDBQADMQAwLgIVAJxmL029GLXDJVbk72d4cSPQ4/rvAhUAll9UPl8aOMEg
+V4egANhwbynMGSgxgc4wgcsCAQEwfjB1MQswCQYDVQQGEwJVUzELMAkGA1UECBMC
+Q0ExEjAQBgNVBAcTCUN1cGVydGlubzEZMBcGA1UEChMQU3VuIE1pY3Jvc3lzdGVt
+czERMA8GA1UECxMISmF2YVNvZnQxFzAVBgNVBAMTDkRvdWdsYXMgSG9vdmVyAgUA
+59UzNDAJBgUrDgMCGgUAMAsGByqGSM44BAMFAAQuMCwCFDmry17kzDD6Y5X1BqIS
+lq6swckPAhRtiXvBHa5CRGjbwk8yqf9hGgZfFA==
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/pkcs/pkcs7/jarsigner/META-INF/PKCS7TEST.SF Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,82 @@
+Signature-Version: 1.0
+
+Name: CheckCerts.class
+Digest-Algorithms: SHA
+SHA-Digest: ya1xwvsQO+DRpQbw3Fh2nRB2JQc=
+
+Name: ContentInfoTest.class
+Digest-Algorithms: SHA
+SHA-Digest: Ca+EJakU6zw4KAhoqcnCpNqk2LI=
+
+Name: JarVerify.class
+Digest-Algorithms: SHA
+SHA-Digest: +DGaWWknfwe4ZOpsoMTFzfWRvhQ=
+
+Name: JarVerify2.class
+Digest-Algorithms: SHA
+SHA-Digest: GqDzYyY4P/WH5HKviWqXttPg5rE=
+
+Name: PKCS7Read.class
+Digest-Algorithms: SHA
+SHA-Digest: Qmf8K9hXVlwIdPY6nv2jFPfGqkA=
+
+Name: PKCS7Test.class
+Digest-Algorithms: SHA
+SHA-Digest: Gbe/gzyv2F58f6EEhSZ1BqGXtlo=
+
+Name: PKCS7Test10.class
+Digest-Algorithms: SHA
+SHA-Digest: 8wBqW//eW2sNRI91bLYEOodcgaE=
+
+Name: PKCS7Test11.class
+Digest-Algorithms: SHA
+SHA-Digest: bXhLKEslcuEXi4u/ahgT2q6tcEU=
+
+Name: PKCS7Test12.class
+Digest-Algorithms: SHA
+SHA-Digest: 9KEY1b52QLmN0qz/5z0wBFrOmz0=
+
+Name: PKCS7Test2.class
+Digest-Algorithms: SHA
+SHA-Digest: +Ua32/2Q8F2brQQmSXX+XS+M/h4=
+
+Name: PKCS7Test3.class
+Digest-Algorithms: SHA
+SHA-Digest: 0HXUZyaSfdeKee8nZzEjRSyreu4=
+
+Name: PKCS7Test4.class
+Digest-Algorithms: SHA
+SHA-Digest: J7yrS24oKuSgautvdzhqBj7dbcQ=
+
+Name: PKCS7Test5.class
+Digest-Algorithms: SHA
+SHA-Digest: JTv9WSox1LESR2Lq7s0UqSltDSQ=
+
+Name: PKCS7Test6.class
+Digest-Algorithms: SHA
+SHA-Digest: gGv+kNh+u3HQ1tzxlcAW7SpFTKk=
+
+Name: PKCS7Test7.class
+Digest-Algorithms: SHA
+SHA-Digest: fiHF1aA1aczs1OwEy8G7VC+r7LI=
+
+Name: PKCS7Test8.class
+Digest-Algorithms: SHA
+SHA-Digest: 74TW7I9VOw5VgLvhRmDfqEWvfAQ=
+
+Name: PKCS7Test9.class
+Digest-Algorithms: SHA
+SHA-Digest: 1cBInGTcO1AQZ+/0vhFkiZWwlA0=
+
+Name: SignerInfoTest.class
+Digest-Algorithms: SHA
+SHA-Digest: cFY4CtSjza1A+WjAKNSVqupjRYE=
+
+Name: SignerInfoTest2.class
+Digest-Algorithms: SHA
+SHA-Digest: aNM0FP0zEzQzxlXx6qCBxukmkHQ=
+
+Name: SimpleSigner.class
+Digest-Algorithms: SHA
+SHA-Digest: /LWCsnC7MZMR6Gow3y2cvp7I0SM=
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/pkcs/pkcs8/PKCS8Test.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8048357
+ * @summary PKCS8 Standards Conformance Tests
+ * @modules java.base/sun.security.pkcs
+ * java.base/sun.security.util
+ * java.base/sun.security.provider
+ * java.base/sun.security.x509
+ * java.base/sun.misc
+ * @compile -XDignore.symbol.file PKCS8Test.java
+ * @run main PKCS8Test
+ */
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.util.Arrays;
+import sun.misc.HexDumpEncoder;
+import sun.security.pkcs.PKCS8Key;
+import sun.security.provider.DSAPrivateKey;
+import sun.security.util.DerOutputStream;
+import sun.security.util.DerValue;
+import sun.security.x509.AlgorithmId;
+
+import static java.lang.System.out;
+
+public class PKCS8Test {
+
+ static final HexDumpEncoder hexDump = new HexDumpEncoder();
+
+ static final DerOutputStream derOutput = new DerOutputStream();
+
+ static final String FORMAT = "PKCS#8";
+ static final String EXPECTED_ALG_ID_CHRS = "DSA\n\tp: 02\n\tq: 03\n"
+ + "\tg: 04\n";
+ static final String ALGORITHM = "DSA";
+ static final String EXCEPTION_MESSAGE = "version mismatch: (supported: "
+ + "00, parsed: 01";
+
+ // test second branch in byte[] encode()
+ // DER encoding,include (empty) set of attributes
+ static final int[] NEW_ENCODED_KEY_INTS = { 0x30,
+ // length 30 = 0x1e
+ 0x1e,
+ // first element
+ // version Version (= INTEGER)
+ 0x02,
+ // length 1
+ 0x01,
+ // value 0
+ 0x00,
+ // second element
+ // privateKeyAlgorithmIdentifier PrivateKeyAlgorithmIdentifier
+ // (sequence)
+ // (an object identifier?)
+ 0x30,
+ // length 18
+ 0x12,
+ // contents
+ // object identifier, 5 bytes
+ 0x06, 0x05,
+ // { 1 3 14 3 2 12 }
+ 0x2b, 0x0e, 0x03, 0x02, 0x0c,
+ // sequence, 9 bytes
+ 0x30, 0x09,
+ // integer 2
+ 0x02, 0x01, 0x02,
+ // integer 3
+ 0x02, 0x01, 0x03,
+ // integer 4
+ 0x02, 0x01, 0x04,
+ // third element
+ // privateKey PrivateKey (= OCTET STRING)
+ 0x04,
+ // length
+ 0x03,
+ // privateKey contents
+ 0x02, 0x01, 0x01,
+ // 4th (optional) element -- attributes [0] IMPLICIT Attributes
+ // OPTIONAL
+ // (Attributes = SET OF Attribute) Here, it will be empty.
+ 0xA0,
+ // length
+ 0x00 };
+
+ // encoding originally created, but with the version changed
+ static final int[] NEW_ENCODED_KEY_INTS_2 = {
+ // sequence
+ 0x30,
+ // length 28 = 0x1c
+ 0x1c,
+ // first element
+ // version Version (= INTEGER)
+ 0x02,
+ // length 1
+ 0x01,
+ // value 1 (illegal)
+ 0x01,
+ // second element
+ // privateKeyAlgorithmIdentifier PrivateKeyAlgorithmIdentifier
+ // (sequence)
+ // (an object identifier?)
+ 0x30,
+ // length 18
+ 0x12,
+ // contents
+ // object identifier, 5 bytes
+ 0x06, 0x05,
+ // { 1 3 14 3 2 12 }
+ 0x2b, 0x0e, 0x03, 0x02, 0x0c,
+ // sequence, 9 bytes
+ 0x30, 0x09,
+ // integer 2
+ 0x02, 0x01, 0x02,
+ // integer 3
+ 0x02, 0x01, 0x03,
+ // integer 4
+ 0x02, 0x01, 0x04,
+ // third element
+ // privateKey PrivateKey (= OCTET STRING)
+ 0x04,
+ // length
+ 0x03,
+ // privateKey contents
+ 0x02, 0x01, 0x01 };
+
+ // 0000: 30 1E 02 01 00 30 14 06 07 2A 86 48 CE 38 04 01 0....0...*.H.8..
+ // 0010: 30 09 02 01 02 02 01 03 02 01 04 04 03 02 01 01 0...............
+ static final int[] EXPECTED = { 0x30,
+ // length 30 = 0x1e
+ 0x1e,
+ // first element
+ // version Version (= INTEGER)
+ 0x02,
+ // length 1
+ 0x01,
+ // value 0
+ 0x00,
+ // second element
+ // privateKeyAlgorithmIdentifier PrivateKeyAlgorithmIdentifier
+ // (sequence)
+ // (an object identifier?)
+ 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x01,
+ // integer 2
+ 0x30, 0x09, 0x02,
+ // integer 3
+ 0x01, 0x02, 0x02,
+ // integer 4
+ 0x01, 0x03, 0x02,
+ // third element
+ // privateKey PrivateKey (= OCTET STRING)
+ 0x01,
+ // length
+ 0x04,
+ // privateKey contents
+ 0x04, 0x03, 0x02,
+ // 4th (optional) element -- attributes [0] IMPLICIT Attributes
+ // OPTIONAL
+ // (Attributes = SET OF Attribute) Here, it will be empty.
+ 0x01,
+ // length
+ 0x01 };
+
+ static void raiseException(String expected, String received) {
+ throw new RuntimeException(
+ "Expected " + expected + "; Received " + received);
+ }
+
+ public static void main(String[] args)
+ throws IOException, InvalidKeyException {
+
+ byte[] encodedKey = getEncodedKey();
+ byte[] expectedBytes = new byte[EXPECTED.length];
+ for (int i = 0; i < EXPECTED.length; i++) {
+ expectedBytes[i] = (byte) EXPECTED[i];
+ }
+
+ dumpByteArray("encodedKey :", encodedKey);
+ if (!Arrays.equals(encodedKey, expectedBytes)) {
+ raiseException(new String(expectedBytes), new String(encodedKey));
+ }
+
+ PKCS8Key decodedKey = PKCS8Key.parse(new DerValue(encodedKey));
+ String alg = decodedKey.getAlgorithm();
+ AlgorithmId algId = decodedKey.getAlgorithmId();
+ out.println("Algorithm :" + alg);
+ out.println("AlgorithmId: " + algId);
+
+ if (!ALGORITHM.equals(alg)) {
+ raiseException(ALGORITHM, alg);
+ }
+ if (!EXPECTED_ALG_ID_CHRS.equalsIgnoreCase(algId.toString())) {
+ raiseException(EXPECTED_ALG_ID_CHRS, algId.toString());
+ }
+
+ decodedKey.encode(derOutput);
+ dumpByteArray("Stream encode: ", derOutput.toByteArray());
+ if (!Arrays.equals(derOutput.toByteArray(), expectedBytes)) {
+ raiseException(new String(expectedBytes), derOutput.toString());
+ }
+
+ dumpByteArray("byte[] encoding: ", decodedKey.getEncoded());
+ if (!Arrays.equals(decodedKey.getEncoded(), expectedBytes)) {
+ raiseException(new String(expectedBytes),
+ new String(decodedKey.getEncoded()));
+ }
+
+ if (!FORMAT.equals(decodedKey.getFormat())) {
+ raiseException(FORMAT, decodedKey.getFormat());
+ }
+
+ try {
+ byte[] newEncodedKey = new byte[NEW_ENCODED_KEY_INTS.length];
+ for (int i = 0; i < newEncodedKey.length; i++) {
+ newEncodedKey[i] = (byte) NEW_ENCODED_KEY_INTS[i];
+ }
+ PKCS8Key newDecodedKey = PKCS8Key
+ .parse(new DerValue(newEncodedKey));
+
+ throw new RuntimeException(
+ "key1: Expected an IOException during " + "parsing");
+ } catch (IOException e) {
+ System.out.println("newEncodedKey: should have excess data due to "
+ + "attributes, which are not supported");
+ }
+
+ try {
+ byte[] newEncodedKey2 = new byte[NEW_ENCODED_KEY_INTS_2.length];
+ for (int i = 0; i < newEncodedKey2.length; i++) {
+ newEncodedKey2[i] = (byte) NEW_ENCODED_KEY_INTS_2[i];
+ }
+
+ PKCS8Key newDecodedKey2 = PKCS8Key
+ .parse(new DerValue(newEncodedKey2));
+
+ throw new RuntimeException(
+ "key2: Expected an IOException during " + "parsing");
+ } catch (IOException e) {
+ out.println("Key 2: should be illegal version");
+ out.println(e.getMessage());
+ if (!EXCEPTION_MESSAGE.equals(e.getMessage())) {
+ throw new RuntimeException("Key2: expected: "
+ + EXCEPTION_MESSAGE + " get: " + e.getMessage());
+ }
+ }
+
+ }
+
+ // get a byte array from somewhere
+ static byte[] getEncodedKey() throws InvalidKeyException {
+ BigInteger p = BigInteger.valueOf(1);
+ BigInteger q = BigInteger.valueOf(2);
+ BigInteger g = BigInteger.valueOf(3);
+ BigInteger x = BigInteger.valueOf(4);
+
+ DSAPrivateKey priv = new DSAPrivateKey(p, q, g, x);
+ return priv.getEncoded();
+ }
+
+ static void dumpByteArray(String nm, byte[] bytes) throws IOException {
+ out.println(nm + " length: " + bytes.length);
+ hexDump.encodeBuffer(bytes, out);
+ }
+
+ static String toString(PKCS8Key key) {
+ StringBuilder builder = new StringBuilder(key.getAlgorithm());
+ builder.append('\n').append("parameters:")
+ .append(key.getAlgorithmId().toString());
+ return builder.toString();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/tools/jarsigner/Options.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8056174
+ * @summary Make sure the jarsigner tool still works after it's modified to
+ * be based on JarSigner API
+ * @library /lib/testlibrary
+ * @modules java.base/sun.security.tools.keytool
+ * jdk.jartool/sun.security.tools.jarsigner
+ * java.base/sun.security.pkcs
+ * java.base/sun.security.x509
+ */
+
+import com.sun.jarsigner.ContentSigner;
+import com.sun.jarsigner.ContentSignerParameters;
+import jdk.testlibrary.JarUtils;
+import sun.security.pkcs.PKCS7;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.*;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+public class Options {
+
+ public static void main(String[] args) throws Exception {
+
+ // Prepares raw file
+ Files.write(Paths.get("a"), "a".getBytes());
+
+ // Pack
+ JarUtils.createJar("a.jar", "a");
+
+ // Prepare a keystore
+ sun.security.tools.keytool.Main.main(
+ ("-keystore jks -storepass changeit -keypass changeit -dname" +
+ " CN=A -alias a -genkeypair -keyalg rsa").split(" "));
+
+ // -altsign
+ sun.security.tools.jarsigner.Main.main(
+ ("-debug -signedjar altsign.jar -keystore jks -storepass changeit" +
+ " -altsigner Options$X a.jar a").split(" "));
+
+ try (JarFile jf = new JarFile("altsign.jar")) {
+ JarEntry je = jf.getJarEntry("META-INF/A.RSA");
+ try (InputStream is = jf.getInputStream(je)) {
+ if (!Arrays.equals(is.readAllBytes(), "1234".getBytes())) {
+ throw new Exception("altsign go wrong");
+ }
+ }
+ }
+
+ // -sigfile, -digestalg, -sigalg, -internalsf, -sectionsonly
+ sun.security.tools.jarsigner.Main.main(
+ ("-debug -signedjar new.jar -keystore jks -storepass changeit" +
+ " -sigfile olala -digestalg SHA1 -sigalg SHA224withRSA" +
+ " -internalsf -sectionsonly a.jar a").split(" "));
+
+ try (JarFile jf = new JarFile("new.jar")) {
+ JarEntry je = jf.getJarEntry("META-INF/OLALA.SF");
+ Objects.requireNonNull(je); // check -sigfile
+ byte[] sf = null; // content of .SF
+ try (InputStream is = jf.getInputStream(je)) {
+ sf = is.readAllBytes(); // save for later comparison
+ Attributes attrs = new Manifest(new ByteArrayInputStream(sf))
+ .getMainAttributes();
+ // check -digestalg
+ if (!attrs.containsKey(new Attributes.Name(
+ "SHA1-Digest-Manifest-Main-Attributes"))) {
+ throw new Exception("digestalg incorrect");
+ }
+ // check -sectionsonly
+ if (attrs.containsKey(new Attributes.Name(
+ "SHA1-Digest-Manifest"))) {
+ throw new Exception("SF should not have file digest");
+ }
+ }
+
+ je = jf.getJarEntry("META-INF/OLALA.RSA");
+ try (InputStream is = jf.getInputStream(je)) {
+ PKCS7 p7 = new PKCS7(is.readAllBytes());
+ String alg = p7.getSignerInfos()[0]
+ .getDigestAlgorithmId().getName();
+ if (!alg.equals("SHA-224")) { // check -sigalg
+ throw new Exception("PKCS7 signing is using " + alg);
+ }
+ // check -internalsf
+ if (!Arrays.equals(sf, p7.getContentInfo().getData())) {
+ throw new Exception("SF not in RSA");
+ }
+ }
+
+ }
+
+ // TSA-related ones are checked in ts.sh
+ }
+
+ public static class X extends ContentSigner {
+ @Override
+ public byte[] generateSignedData(ContentSignerParameters parameters,
+ boolean omitContent, boolean applyTimestamp)
+ throws NoSuchAlgorithmException, CertificateException,
+ IOException {
+ return "1234".getBytes();
+ }
+ }
+}
--- a/jdk/test/sun/tools/jhsdb/BasicLauncherTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/tools/jhsdb/BasicLauncherTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -24,7 +24,7 @@
/*
* @test
* @summary Basic test for jhsdb launcher
- * @library /../../test/lib/share/classes
+ * @library /test/lib/share/classes
* @library /lib/testlibrary
* @build jdk.testlibrary.*
* @build jdk.test.lib.apps.*
--- a/jdk/test/sun/tools/jmap/BasicJMapTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/tools/jmap/BasicJMapTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -38,7 +38,7 @@
* @summary Unit test for jmap utility
* @key intermittent
* @library /lib/testlibrary
- * @library /../../test/lib/share/classes
+ * @library /test/lib/share/classes
* @modules java.management
* @build jdk.testlibrary.*
* @build jdk.test.lib.hprof.*
--- a/jdk/test/sun/tools/jmap/heapconfig/JMapHeapConfigTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/tools/jmap/heapconfig/JMapHeapConfigTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -36,7 +36,7 @@
* @test
* @bug 8042397
* @summary Unit test for jmap utility test heap configuration reader
- * @library /../../test/lib/share/classes
+ * @library /test/lib/share/classes
* @library /lib/testlibrary
* @modules java.management
* @build jdk.testlibrary.*
--- a/jdk/test/sun/tools/jstack/DeadlockDetectionTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/tools/jstack/DeadlockDetectionTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -37,7 +37,7 @@
/*
* @test
* @summary Test deadlock detection
- * @library /../../test/lib/share/classes
+ * @library /test/lib/share/classes
* @library /lib/testlibrary
* @modules java.management
* @build jdk.testlibrary.*
--- a/jdk/test/sun/util/logging/PlatformLoggerTest.java Fri Nov 20 15:40:23 2015 -0800
+++ b/jdk/test/sun/util/logging/PlatformLoggerTest.java Wed Jul 05 21:02:29 2017 +0200
@@ -38,7 +38,6 @@
import java.lang.reflect.Modifier;
import java.util.logging.*;
import sun.util.logging.PlatformLogger;
-import sun.util.logging.LoggingSupport;
import static sun.util.logging.PlatformLogger.Level.*;
public class PlatformLoggerTest {
@@ -195,7 +194,9 @@
System.out.println("Testing Java Level with: " + level.getName());
// create a brand new java logger
- Logger javaLogger = (Logger) LoggingSupport.getLogger(logger.getName()+"."+level.getName());
+ Logger javaLogger = sun.util.logging.internal.LoggingProviderImpl.getLogManagerAccess()
+ .demandLoggerFor(LogManager.getLogManager(),
+ logger.getName()+"."+level.getName(), Thread.class);
// Set a non standard java.util.logging.Level on the java logger
// (except for OFF & ALL - which will remain unchanged)
--- a/make/CompileJavaModules.gmk Fri Nov 20 15:40:23 2015 -0800
+++ b/make/CompileJavaModules.gmk Wed Jul 05 21:02:29 2017 +0200
@@ -369,7 +369,7 @@
################################################################################
-jdk.javadoc_COPY := .xml .css .js
+jdk.javadoc_COPY := .xml .css .js .png
################################################################################
--- a/make/Main.gmk Fri Nov 20 15:40:23 2015 -0800
+++ b/make/Main.gmk Wed Jul 05 21:02:29 2017 +0200
@@ -482,6 +482,8 @@
test-hotspot-jtreg: jimages test-image
+ install: product-images
+
endif
################################################################################
--- a/modules.xml Fri Nov 20 15:40:23 2015 -0800
+++ b/modules.xml Wed Jul 05 21:02:29 2017 +0200
@@ -459,6 +459,10 @@
<to>jdk.localedata</to>
</export>
<export>
+ <name>jdk.internal.logger</name>
+ <to>java.logging</to>
+ </export>
+ <export>
<name>sun.util.logging</name>
<to>java.desktop</to>
<to>java.logging</to>
@@ -1707,6 +1711,9 @@
<export>
<name>com.sun.jarsigner</name>
</export>
+ <export>
+ <name>jdk.security.jarsigner</name>
+ </export>
</module>
<module>
<name>jdk.javadoc</name>
--- a/nashorn/.hgtags Fri Nov 20 15:40:23 2015 -0800
+++ b/nashorn/.hgtags Wed Jul 05 21:02:29 2017 +0200
@@ -326,3 +326,4 @@
bc92163c4e0aa3fcca51a290c55715c54a5faa5f jdk9-b90
fee4d2015e24ced4f28f4dcf93076a4fbd03844d jdk9-b91
34b77a618e98c5da59a760341f43af6aefc56efb jdk9-b92
+e13533f7bb78da49bbd909fdf22e13e0e2538146 jdk9-b93
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Fri Nov 20 15:40:23 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Jul 05 21:02:29 2017 +0200
@@ -550,7 +550,10 @@
if (swap) {
method.swap();
}
- for (int i = 0; i < depth; i++) {
+ if (depth > 1) {
+ method.load(depth);
+ method.invoke(ScriptObject.GET_PROTO_DEPTH);
+ } else {
method.invoke(ScriptObject.GET_PROTO);
}
if (swap) {
@@ -1379,7 +1382,10 @@
return;
}
method.loadCompilerConstant(SCOPE);
- for(int i = 0; i < count; ++i) {
+ if (count > 1) {
+ method.load(count);
+ method.invoke(ScriptObject.GET_PROTO_DEPTH);
+ } else {
method.invoke(ScriptObject.GET_PROTO);
}
method.storeCompilerConstant(SCOPE);
@@ -3317,9 +3323,6 @@
if (needsScope) {
method.loadCompilerConstant(SCOPE);
- }
-
- if (needsScope) {
loadExpressionUnbounded(init);
// block scoped variables need a DECLARE flag to signal end of temporal dead zone (TDZ)
final int flags = getScopeCallSiteFlags(identSymbol) | (varNode.isBlockScoped() ? CALLSITE_DECLARE : 0);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java Fri Nov 20 15:40:23 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java Wed Jul 05 21:02:29 2017 +0200
@@ -46,6 +46,7 @@
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.logging.Level;
@@ -684,7 +685,7 @@
if (time > 0L && timeLogger != null) {
assert env.isTimingEnabled();
- sb.append(" in ").append(time).append(" ms");
+ sb.append(" in ").append(TimeUnit.NANOSECONDS.toMillis(time)).append(" ms");
}
log.info(sb);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java Fri Nov 20 15:40:23 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java Wed Jul 05 21:02:29 2017 +0200
@@ -239,7 +239,7 @@
private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL;
/** Does this function need to store all its variables in scope? */
- private static final int HAS_ALL_VARS_IN_SCOPE = HAS_DEEP_EVAL;
+ public static final int HAS_ALL_VARS_IN_SCOPE = HAS_DEEP_EVAL;
/** Does this function potentially need "arguments"? Note that this is not a full test, as further negative check of REDEFINES_ARGS is needed. */
private static final int MAYBE_NEEDS_ARGUMENTS = USES_ARGUMENTS | HAS_EVAL;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDebug.java Fri Nov 20 15:40:23 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDebug.java Wed Jul 05 21:02:29 2017 +0200
@@ -224,6 +224,18 @@
}
/**
+ * Returns {@code true} if passed object is a function that is fully debuggable (has all vars in scope).
+ *
+ * @param self self reference
+ * @param obj object
+ * @return true {@code obj} is a debuggable function
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ public static Object isDebuggableFunction(final Object self, final Object obj) {
+ return (obj instanceof ScriptFunction && ((ScriptFunction) obj).hasAllVarsInScope());
+ }
+
+ /**
* Returns the property listener count for a script object
*
* @param self self reference
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/AbstractParser.java Fri Nov 20 15:40:23 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/AbstractParser.java Wed Jul 05 21:02:29 2017 +0200
@@ -103,6 +103,9 @@
* @param lineOffset Offset from which lines should be counted
*/
protected AbstractParser(final Source source, final ErrorManager errors, final boolean strict, final int lineOffset) {
+ if (source.getLength() > Token.LENGTH_MASK) {
+ throw new RuntimeException("Source exceeds size limit of " + Token.LENGTH_MASK + " bytes");
+ }
this.source = source;
this.errors = errors;
this.k = -1;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java Fri Nov 20 15:40:23 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java Wed Jul 05 21:02:29 2017 +0200
@@ -213,7 +213,6 @@
* function body. This is used with the feature where the parser is skipping nested function bodies to
* avoid reading ahead unnecessarily when we skip the function bodies.
*/
-
public Lexer(final Source source, final int start, final int len, final TokenStream stream, final boolean scripting, final boolean es6, final boolean pauseOnFunctionBody) {
super(source.getContent(), 1, start, len);
this.source = source;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Fri Nov 20 15:40:23 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Wed Jul 05 21:02:29 2017 +0200
@@ -2941,6 +2941,10 @@
try {
// Create a new function block.
body = newBlock();
+ if (env._debug_scopes) {
+ // debug scope options forces everything to be in scope
+ markEval(lc);
+ }
assert functionNode != null;
final int functionId = functionNode.getId();
parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Token.java Fri Nov 20 15:40:23 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Token.java Wed Jul 05 21:02:29 2017 +0200
@@ -30,11 +30,21 @@
import jdk.nashorn.internal.runtime.Source;
/**
- * Basic parse/lex unit.
- *
+ * A token is a 64 bit long value that represents a basic parse/lex unit.
+ * This class provides static methods to manipulate lexer tokens.
*/
public class Token {
+ /**
+ * We use 28 bits for the position and 28 bits for the length of the token.
+ * This limits the maximal length of code we can handle to 2 ^ 28 - 1 bytes.
+ */
+ public final static int LENGTH_MASK = 0xfffffff;
+
+ // The first 8 bits are used for the token type, followed by length and position
+ private final static int LENGTH_SHIFT = 8;
+ private final static int POSITION_SHIFT = 36;
+
private Token() {
}
@@ -46,8 +56,9 @@
* @return Token descriptor.
*/
public static long toDesc(final TokenType type, final int position, final int length) {
- return (long)position << 32 |
- (long)length << 8 |
+ assert position <= LENGTH_MASK && length <= LENGTH_MASK;
+ return (long)position << POSITION_SHIFT |
+ (long)length << LENGTH_SHIFT |
type.ordinal();
}
@@ -57,7 +68,7 @@
* @return Start position of the token in the source.
*/
public static int descPosition(final long token) {
- return (int)(token >>> 32);
+ return (int)(token >>> POSITION_SHIFT);
}
/**
@@ -98,7 +109,7 @@
* @return Length of the token.
*/
public static int descLength(final long token) {
- return (int)token >>> 8;
+ return (int)((token >>> LENGTH_SHIFT) & LENGTH_MASK);
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java Fri Nov 20 15:40:23 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java Wed Jul 05 21:02:29 2017 +0200
@@ -81,6 +81,9 @@
/** Generate line number table in class files */
public final boolean _debug_lines;
+ /** Put all variables in scopes to make them debuggable */
+ public final boolean _debug_scopes;
+
/** Directory in which source files and generated class files are dumped */
public final String _dest_dir;
@@ -246,6 +249,7 @@
_compile_only = options.getBoolean("compile.only");
_const_as_var = options.getBoolean("const.as.var");
_debug_lines = options.getBoolean("debug.lines");
+ _debug_scopes = options.getBoolean("debug.scopes");
_dest_dir = options.getString("d");
_dump_on_error = options.getBoolean("doe");
_early_lvalue_error = options.getBoolean("early.lvalue.error");
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java Fri Nov 20 15:40:23 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java Wed Jul 05 21:02:29 2017 +0200
@@ -51,6 +51,7 @@
import jdk.nashorn.internal.codegen.ApplySpecialization;
import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
+import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.objects.NativeFunction;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
@@ -472,6 +473,15 @@
}
/**
+ * Is this is a function with all variables in scope?
+ * @return true if function has all
+ */
+ public boolean hasAllVarsInScope() {
+ return data instanceof RecompilableScriptFunctionData &&
+ (((RecompilableScriptFunctionData) data).getFunctionFlags() & FunctionNode.HAS_ALL_VARS_IN_SCOPE) != 0;
+ }
+
+ /**
* Returns true if this is a non-strict, non-built-in function that requires
* non-primitive this argument according to ECMA 10.4.3.
*
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Fri Nov 20 15:40:23 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Wed Jul 05 21:02:29 2017 +0200
@@ -1244,7 +1244,7 @@
public final ScriptObject getProto(final int n) {
assert n > 0;
ScriptObject p = getProto();
- for (int i = n; i-- > 0;) {
+ for (int i = n; --i > 0;) {
p = p.getProto();
}
return p;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Symbol.java Fri Nov 20 15:40:23 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Symbol.java Wed Jul 05 21:02:29 2017 +0200
@@ -26,6 +26,7 @@
package jdk.nashorn.internal.runtime;
import java.io.Serializable;
+import jdk.nashorn.internal.objects.NativeSymbol;
/**
* This class represents a unique, non-String Object property key as defined in ECMAScript 6.
@@ -56,4 +57,29 @@
public final String getName() {
return name;
}
+
+ private Object writeReplace() {
+ // If this symbol is a globally registered one, replace it with a
+ // GlobalSymbol in serialized stream.
+ return NativeSymbol.keyFor(null, this) == name ? new GlobalSymbol(name) : this;
+ }
+
+ /**
+ * Represents a globally registered (with NativeSymbol._for) symbol in the
+ * serialized stream. Upon deserialization, it resolves to the globally
+ * registered symbol.
+ */
+ private static class GlobalSymbol implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final String name;
+
+ GlobalSymbol(final String name) {
+ this.name = name;
+ }
+
+ private Object readResolve() {
+ return NativeSymbol._for(null, name);
+ }
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Options.properties Fri Nov 20 15:40:23 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Options.properties Wed Jul 05 21:02:29 2017 +0200
@@ -77,6 +77,15 @@
desc="Print extended help for command line flags." \
}
+nashorn.option.anonymous.classes = { \
+ name="--anonymous-classes", \
+ is_undocumented=true, \
+ params=[auto|true|false], \
+ default=auto, \
+ type=string, \
+ desc="Use VM anonymous classes for compiled scripts." \
+}
+
nashorn.option.class.cache.size ={ \
name="--class-cache-size", \
short_name="-ccs", \
@@ -118,6 +127,31 @@
type=String \
}
+nashorn.option.D = { \
+ name="-D", \
+ desc="-Dname=value. Set a system property. This option can be repeated.", \
+ type=String \
+}
+
+nashorn.option.debug.lines = { \
+ name="--debug-lines", \
+ is_undocumented=true, \
+ desc="Generate line number table in .class files.", \
+ default=true \
+}
+
+nashorn.option.debug.locals = { \
+ name="--debug-locals", \
+ is_undocumented=true, \
+ desc="Generate local variable table in .class files." \
+}
+
+nashorn.option.debug.scopes = { \
+ name="--debug-scopes", \
+ is_undocumented=true, \
+ desc="Put all variables in scopes to make them debuggable." \
+}
+
nashorn.option.doe = { \
name="-dump-on-error", \
short_name="-doe", \
@@ -172,6 +206,14 @@
default=false \
}
+nashorn.option.language = { \
+ name="--language", \
+ type=String, \
+ params=[es5|es6], \
+ default=es5, \
+ desc="Specify ECMAScript language version." \
+}
+
nashorn.option.log = { \
name="--log", \
is_undocumented=true, \
@@ -181,19 +223,6 @@
type=Log \
}
-nashorn.option.debug.lines = { \
- name="--debug-lines", \
- is_undocumented=true, \
- desc="Generate line number table in .class files.", \
- default=true \
-}
-
-nashorn.option.debug.locals = { \
- name="--debug-locals", \
- is_undocumented=true, \
- desc="Generate local variable table in .class files." \
-}
-
nashorn.option.lazy.compilation = { \
name="--lazy-compilation", \
is_undocumented=true, \
@@ -201,13 +230,6 @@
default=true \
}
-nashorn.option.optimistic.types = { \
- name="--optimistic-types", \
- short_name="-ot", \
- desc="Use optimistic type assumptions with deoptimizing recompilation. This makes the compiler try, for any program symbol whose type cannot be proven at compile time, to type it as narrow and primitive as possible. If the runtime encounters an error because symbol type is too narrow, a wider method will be generated until steady stage is reached. While this produces as optimal Java Bytecode as possible, erroneous type guesses will lead to longer warmup. Optimistic typing is currently enabled by default, but can be disabled for faster startup performance.", \
- default=true \
-}
-
nashorn.option.loader.per.compile = { \
name="--loader-per-compile", \
is_undocumented=true, \
@@ -239,6 +261,13 @@
default=false \
}
+nashorn.option.optimistic.types = { \
+ name="--optimistic-types", \
+ short_name="-ot", \
+ desc="Use optimistic type assumptions with deoptimizing recompilation. This makes the compiler try, for any program symbol whose type cannot be proven at compile time, to type it as narrow and primitive as possible. If the runtime encounters an error because symbol type is too narrow, a wider method will be generated until steady stage is reached. While this produces as optimal Java Bytecode as possible, erroneous type guesses will lead to longer warmup. Optimistic typing is currently enabled by default, but can be disabled for faster startup performance.", \
+ default=true \
+}
+
nashorn.option.parse.only = { \
name="--parse-only", \
is_undocumented=true, \
@@ -313,12 +342,6 @@
desc="Print the symbol table." \
}
-nashorn.option.D = { \
- name="-D", \
- desc="-Dname=value. Set a system property. This option can be repeated.", \
- type=String \
-}
-
nashorn.option.strict = { \
name="-strict", \
desc="Run scripts in strict mode." \
@@ -329,14 +352,6 @@
desc="Enable scripting features." \
}
-nashorn.option.language = { \
- name="--language", \
- type=String, \
- params=[es5|es6], \
- default=es5, \
- desc="Specify ECMAScript language version." \
-}
-
nashorn.option.stdout = { \
name="--stdout", \
is_undocumented=true, \
@@ -380,20 +395,11 @@
enterexit [trace callsite enter/exit], objects [print object properties]." \
}
-nashorn.option.anonymous.classes = { \
- name="--anonymous-classes", \
- is_undocumented=true, \
- params=[auto|true|false], \
- default=auto, \
- type=string, \
- desc="Use VM anonymous classes for compiled scripts." \
-}
-
nashorn.option.unstable.relink.threshold ={ \
name="--unstable-relink-threshold", \
short_name="-urt", \
- desc="Number of times a dynamic call site has to be \
- relinked before it is considered unstable, when the \
+ desc="Number of times a dynamic call site has to be \
+ relinked before it is considered unstable, when the \
runtime will try to link it as if it is megamorphic.", \
is_undocumented=true, \
type=Integer, \
--- a/nashorn/test/TEST.ROOT Fri Nov 20 15:40:23 2015 -0800
+++ b/nashorn/test/TEST.ROOT Wed Jul 05 21:02:29 2017 +0200
@@ -8,4 +8,4 @@
groups=TEST.groups
# Minimum jtreg version
-requiredVersion=4.1 b11
+requiredVersion=4.1 b12
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8059934.js Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8059934: Random failures when script size exceeds token limits
+ *
+ * @test
+ * @run
+ */
+
+// Make sure that we can successfully evaluate a 100 MB string.
+// We don't go beyond that as we'd likely hit heap size limits.
+var src = "var x = 'ok';";
+for (var i = 0; i < 1000000; i++) {
+ src += " ";
+}
+src += "x;";
+
+Assert.assertEquals(100000015, src.length);
+Assert.assertEquals("ok", eval(src));
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8131929.js Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8131929: Add option for debuggable scopes
+ *
+ * @test
+ * @run
+ * @option --debug-scopes=true
+ * @option -Dnashorn.debug
+ * @fork
+ */
+
+
+function f1(x, y) {
+ var a = x * 2 , b = y + 3;
+ print(a, b);
+ return a + b;
+}
+
+function f2() {}
+
+Assert.assertTrue(Debug.isDebuggableFunction(f1));
+Assert.assertTrue(Debug.isDebuggableFunction(f2));
+Assert.assertTrue(Debug.isDebuggableFunction((function() { return function() {}})()));
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8131929_prototype.js Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8131929: Add option for debuggable scopes
+ *
+ * @test
+ * @runif external.prototype
+ * @option --debug-scopes=true
+ * @fork
+ */
+
+load(__DIR__ + 'prototype.js');
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8131929_prototype.js.EXPECTED Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,1 @@
+parsed and compiled ok prototype.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8131929_yui.js Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8131929: Add option for debuggable scopes
+ *
+ * @test
+ * @runif external.yui
+ * @option --debug-scopes=true
+ * @fork
+ */
+
+load(__DIR__ + 'yui.js');
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8131929_yui.js.EXPECTED Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,2 @@
+parsed and compiled ok yui-min.js
+parsed and compiled ok yui.js
--- a/nashorn/test/script/basic/prototype.js Fri Nov 20 15:40:23 2015 -0800
+++ b/nashorn/test/script/basic/prototype.js Wed Jul 05 21:02:29 2017 +0200
@@ -22,7 +22,7 @@
*/
/**
- * NASHORN-467 - check that prootype.js parses and compiles
+ * NASHORN-467 - check that prototype.js parses and compiles
*
* @test
* @runif external.prototype
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/nashorn/internal/runtime/test/JDK_8142924_Test.java Wed Jul 05 21:02:29 2017 +0200
@@ -0,0 +1,43 @@
+package jdk.nashorn.internal.runtime.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import jdk.nashorn.internal.objects.NativeSymbol;
+import jdk.nashorn.internal.runtime.Symbol;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * @bug 8142924
+ * @summary ES6 symbols created with Symbol.for should deserialize to canonical instances
+ */
+@SuppressWarnings("javadoc")
+public class JDK_8142924_Test {
+ @Test
+ public static void testNonGlobal() throws Exception {
+ final String name = "testNonGlobal";
+ final Symbol symbol1 = (Symbol)NativeSymbol.constructor(false, null, name);
+ final Symbol symbol2 = serializeRoundTrip(symbol1);
+ Assert.assertNotSame(symbol1, symbol2);
+ Assert.assertEquals(symbol2.getName(), name);
+ Assert.assertNotSame(symbol1, NativeSymbol._for(null, name));
+ }
+
+ @Test
+ public static void testGlobal() throws Exception {
+ final String name = "testGlobal";
+ final Symbol symbol1 = (Symbol)NativeSymbol._for(null, name);
+ final Symbol symbol2 = serializeRoundTrip(symbol1);
+ Assert.assertSame(symbol1, symbol2);
+ }
+
+ private static Symbol serializeRoundTrip(final Symbol symbol) throws Exception {
+ final ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ final ObjectOutputStream out = new ObjectOutputStream(bout);
+ out.writeObject(symbol);
+ out.close();
+ return (Symbol) new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray())).readObject();
+ }
+}